summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-4.8.1/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-4.8.1/i18n')
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/Makefile.in188
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/alphaindex.cpp1320
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/anytrans.cpp386
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/anytrans.h129
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/astro.cpp1590
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/astro.h755
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/basictz.cpp560
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/bms.cpp155
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/bmsearch.cpp827
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/bocsu.cpp153
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/bocsu.h165
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/brktrans.cpp188
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/brktrans.h113
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/buddhcal.cpp212
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/buddhcal.h243
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/calendar.cpp3418
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/casetrn.cpp191
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/casetrn.h104
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/cecal.cpp149
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/cecal.h134
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.cpp865
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.h294
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/choicfmt.cpp598
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/coleitr.cpp485
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/coll.cpp880
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/colldata.cpp1102
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/coptccal.cpp178
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/coptccal.h272
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.cpp616
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.h230
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csdetect.cpp414
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csdetect.h56
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csmatch.cpp61
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csmatch.h44
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csr2022.cpp175
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csr2022.h86
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrecog.cpp28
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrecog.h42
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrmbcs.cpp519
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrmbcs.h205
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.cpp1350
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.h427
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrucode.cpp146
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrucode.h106
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrutf8.cpp111
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/csrutf8.h42
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/curramt.cpp50
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/currfmt.cpp72
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/currfmt.h101
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/currpinf.cpp388
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/currunit.cpp62
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/datefmt.cpp513
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dcfmtsym.cpp450
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decContext.c435
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decContext.h267
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decNumber.c8143
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decNumber.h196
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decNumberLocal.h735
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.cpp241
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.h59
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/decimfmt.cpp4834
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/digitlst.cpp875
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/digitlst.h400
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtfmtsym.cpp1606
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtitv_impl.h93
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtitvfmt.cpp1477
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtitvinf.cpp650
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtptngen.cpp2156
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtptngen_impl.h259
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/dtrule.cpp139
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/esctrn.cpp179
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/esctrn.h142
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.cpp214
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.h300
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/fmtable.cpp866
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/fmtable_cnv.cpp44
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/format.cpp213
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.cpp120
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.h73
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/fpositer.cpp109
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.cpp125
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.h119
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/gregocal.cpp1356
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/gregoimp.cpp328
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/gregoimp.h364
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/hebrwcal.cpp758
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/hebrwcal.h486
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/i18n.rc108
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj1527
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj.filters1001
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/indiancal.cpp449
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/indiancal.h372
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/inputext.cpp164
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/inputext.h61
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/islamcal.cpp549
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/islamcal.h463
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/japancal.cpp531
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/japancal.h217
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/locdspnm.cpp694
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/measfmt.cpp44
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/measure.cpp67
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/msgfmt.cpp1805
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/msgfmt_impl.h43
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/name2uni.cpp255
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/name2uni.h91
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfrlist.h97
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfrs.cpp945
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfrs.h106
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfrule.cpp1475
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfrule.h114
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfsubs.cpp1317
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nfsubs.h266
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nortrans.cpp175
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nortrans.h100
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nultrans.cpp36
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/nultrans.h71
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/numfmt.cpp1312
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/numsys.cpp247
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/olsontz.cpp1065
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/olsontz.h446
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/persncal.cpp465
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/persncal.h364
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/plurfmt.cpp458
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/plurrule.cpp1432
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/plurrule_impl.h216
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/quant.cpp146
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/quant.h124
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbnf.cpp1623
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt.cpp295
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt.h473
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_data.cpp117
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_data.h152
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_pars.cpp1733
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_pars.h355
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_rule.cpp556
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_rule.h308
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_set.cpp466
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbt_set.h165
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rbtz.cpp934
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.cpp4324
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.h229
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regexcst.h504
-rwxr-xr-xBuild/source/libs/icu/icu-4.8.1/i18n/regexcst.pl328
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regexcst.txt467
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regeximp.h357
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regexst.cpp294
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regexst.h58
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regextxt.cpp45
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/regextxt.h48
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.cpp482
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.h312
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/rematch.cpp6114
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/remtrans.cpp68
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/remtrans.h78
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/repattrn.cpp817
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/search.cpp443
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/selfmt.cpp195
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/selfmtimpl.h92
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/simpletz.cpp1221
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/smpdtfmt.cpp3556
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.cpp158
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.h52
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/sortkey.cpp407
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/strmatch.cpp289
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/strmatch.h250
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/strrepl.cpp328
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/strrepl.h161
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/stsearch.cpp509
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/taiwncal.cpp220
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/taiwncal.h225
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tblcoll.cpp767
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/timezone.cpp1608
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/titletrn.cpp167
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/titletrn.h90
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tmunit.cpp117
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tmutamt.cpp76
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tmutfmt.cpp885
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tolowtrn.cpp65
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tolowtrn.h74
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/toupptrn.cpp65
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/toupptrn.h74
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/translit.cpp1644
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/transreg.cpp1359
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/transreg.h462
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tridpars.cpp938
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tridpars.h361
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.cpp534
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.h65
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.cpp1062
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.h115
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tznames.cpp300
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tznames.h81
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.cpp1426
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.h212
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tzrule.cpp627
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/tztrans.cpp146
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucal.cpp705
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.c60
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.h63
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol.cpp8237
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.cpp1417
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.h59
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.cpp587
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.h102
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_elm.cpp2064
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_elm.h146
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_imp.h1171
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_res.cpp1388
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_sit.cpp911
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.cpp2452
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.h211
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.cpp577
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.h70
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucoleitr.cpp784
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucsdet.cpp180
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucurr.cpp2421
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ucurrimp.h59
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/udat.cpp968
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/udateintervalformat.cpp106
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/udatpg.cpp271
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ulocdata.c343
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/umsg.cpp709
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/umsg_imp.h45
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unesctrn.cpp290
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unesctrn.h110
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uni2name.cpp120
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uni2name.h87
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/alphaindex.h720
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/basictz.h210
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/bms.h274
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/bmsearch.h226
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/calendar.h2258
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/choicfmt.h685
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/coleitr.h400
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/coll.h1141
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/colldata.h452
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/curramt.h130
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/currpinf.h260
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/currunit.h117
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/datefmt.h751
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/dcfmtsym.h450
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/decimfmt.h2320
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtfmtsym.h748
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvfmt.h992
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvinf.h527
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtptngen.h474
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtrule.h250
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/fieldpos.h291
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/fmtable.h673
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/format.h303
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/fpositer.h120
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/gregocal.h815
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/locdspnm.h188
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/measfmt.h77
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/measunit.h71
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/measure.h137
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/msgfmt.h1089
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/numfmt.h1062
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/numsys.h191
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurfmt.h552
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurrule.h381
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbnf.h1059
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbtz.h361
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/regex.h1861
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/search.h575
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/selfmt.h367
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/simpletz.h927
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/smpdtfmt.h1238
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/sortkey.h329
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/stsearch.h518
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/tblcoll.h993
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/timezone.h853
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmunit.h149
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutamt.h168
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutfmt.h270
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/translit.h1320
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/tzrule.h828
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/tztrans.h195
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucal.h1368
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucol.h1325
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucoleitr.h330
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucsdet.h370
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucurr.h349
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/udat.h997
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/udateintervalformat.h178
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/udatpg.h586
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/uldnames.h270
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/ulocdata.h275
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/umsg.h623
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/unirepl.h97
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/unum.h1053
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/upluralrules.h104
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/uregex.h1605
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/usearch.h834
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/uspoof.h887
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/utmscale.h481
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/utrans.h603
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unicode/vtzone.h455
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/unum.cpp908
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/upluralrules.cpp51
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uregex.cpp1942
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uregexc.cpp40
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/usearch.cpp4842
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof.cpp829
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_build.cpp85
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.cpp603
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.h132
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.cpp976
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.h407
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.cpp431
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.h70
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/usrchimp.h140
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/utmscale.c114
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/utrans.cpp495
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/vtzone.cpp2625
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/vzone.cpp185
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/vzone.h360
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.cpp321
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.h140
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/winnmfmt.cpp354
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/winnmfmt.h161
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.cpp157
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.h37
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.cpp844
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.h99
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/zrule.cpp149
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/zrule.h279
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ztrans.cpp101
-rw-r--r--Build/source/libs/icu/icu-4.8.1/i18n/ztrans.h172
329 files changed, 201753 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/Makefile.in b/Build/source/libs/icu/icu-4.8.1/i18n/Makefile.in
new file mode 100644
index 00000000000..22c60061dc9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/Makefile.in
@@ -0,0 +1,188 @@
+#******************************************************************************
+#
+# Copyright (C) 1998-2011, 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) $(CPPFLAGSICUI18N)
+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 numsys.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 chnsecal.o cecal.o coptccal.o ethpccal.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 brktrans.o \
+regexcmp.o rematch.o repattrn.o regexst.o regextxt.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 \
+wintzimpl.o windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o zonemeta.o \
+upluralrules.o plurrule.o plurfmt.o selfmt.o dtitvfmt.o dtitvinf.o udateintervalformat.o \
+tmunit.o tmutamt.o tmutfmt.o colldata.o bmsearch.o bms.o currpinf.o \
+uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o decfmtst.o smpdtfst.o \
+ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
+decNumber.o decContext.o alphaindex.o tznames.o tznames_impl.o tzgnames.o \
+tzfmt.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-4.8.1/i18n/alphaindex.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/alphaindex.cpp
new file mode 100644
index 00000000000..cf247709a5f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/alphaindex.cpp
@@ -0,0 +1,1320 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C API: AlphabeticIndex class
+ */
+
+#include "unicode/utypes.h"
+
+#include "unicode/alphaindex.h"
+#include "unicode/coll.h"
+#include "unicode/normalizer2.h"
+#include "unicode/strenum.h"
+#include "unicode/tblcoll.h"
+#include "unicode/ulocdata.h"
+#include "unicode/uniset.h"
+#include "unicode/uobject.h"
+#include "unicode/uscript.h"
+#include "unicode/usetiter.h"
+#include "unicode/ustring.h"
+
+#include "cstring.h"
+#include "mutex.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uhash.h"
+#include "uvector.h"
+
+//#include <string>
+#include <iostream>
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(AlphabeticIndex)
+
+// Forward Declarations
+static int32_t U_CALLCONV
+PreferenceComparator(const void *context, const void *left, const void *right);
+
+static int32_t U_CALLCONV
+sortCollateComparator(const void *context, const void *left, const void *right);
+
+static int32_t U_CALLCONV
+recordCompareFn(const void *context, const void *left, const void *right);
+
+//
+// UHash support function, delete a UnicodeSet
+// TODO: move this function into uhash.
+//
+static void U_CALLCONV
+uhash_deleteUnicodeSet(void *obj) {
+ delete static_cast<UnicodeSet *>(obj);
+}
+
+// UVector<Bucket *> support function, delete a Bucket.
+static void U_CALLCONV
+alphaIndex_deleteBucket(void *obj) {
+ delete static_cast<AlphabeticIndex::Bucket *>(obj);
+}
+
+// UVector<Record *> support function, delete a Record.
+static void U_CALLCONV
+alphaIndex_deleteRecord(void *obj) {
+ delete static_cast<AlphabeticIndex::Record *>(obj);
+}
+
+
+
+static const Normalizer2 *nfkdNormalizer;
+
+//
+// Append the contents of a UnicodeSet to a UVector of UnicodeStrings.
+// Append everything - individual characters are handled as strings of length 1.
+// The destination vector owns the appended strings.
+
+static void appendUnicodeSetToUVector(UVector &dest, const UnicodeSet &source, UErrorCode &status) {
+ UnicodeSetIterator setIter(source);
+ while (setIter.next()) {
+ const UnicodeString &str = setIter.getString();
+ dest.addElement(str.clone(), status);
+ }
+}
+
+
+AlphabeticIndex::AlphabeticIndex(const Locale &locale, UErrorCode &status) {
+ init(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ locale_ = locale;
+ langType_ = langTypeFromLocale(locale_);
+
+ collator_ = Collator::createInstance(locale, status);
+ if (collator_ != NULL) {
+ collatorPrimaryOnly_ = collator_->clone();
+ }
+ if (collatorPrimaryOnly_ != NULL) {
+ collatorPrimaryOnly_->setStrength(Collator::PRIMARY);
+ }
+ getIndexExemplars(*initialLabels_, locale, status);
+ indexBuildRequired_ = TRUE;
+ if ((collator_ == NULL || collatorPrimaryOnly_ == NULL) && U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ firstScriptCharacters_ = firstStringsInScript(status);
+}
+
+
+AlphabeticIndex::~AlphabeticIndex() {
+ uhash_close(alreadyIn_);
+ delete bucketList_;
+ delete collator_;
+ delete collatorPrimaryOnly_;
+ delete firstScriptCharacters_;
+ delete labels_;
+ delete inputRecords_;
+ delete noDistinctSorting_;
+ delete notAlphabetic_;
+ delete initialLabels_;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::addLabels(const UnicodeSet &additions, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ initialLabels_->addAll(additions);
+ return *this;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::addLabels(const Locale &locale, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ UnicodeSet additions;
+ getIndexExemplars(additions, locale, status);
+ initialLabels_->addAll(additions);
+ return *this;
+}
+
+
+int32_t AlphabeticIndex::getBucketCount(UErrorCode &status) {
+ buildIndex(status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ return bucketList_->size();
+}
+
+
+int32_t AlphabeticIndex::getRecordCount(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ return inputRecords_->size();
+}
+
+
+void AlphabeticIndex::buildIndex(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (!indexBuildRequired_) {
+ return;
+ }
+
+ // Discard any already-built data.
+ // This is important when the user builds and uses an index, then subsequently modifies it,
+ // necessitating a rebuild.
+
+ bucketList_->removeAllElements();
+ labels_->removeAllElements();
+ uhash_removeAll(alreadyIn_);
+ noDistinctSorting_->clear();
+ notAlphabetic_->clear();
+
+ // first sort the incoming Labels, with a "best" ordering among items
+ // that are the same according to the collator
+
+ UVector preferenceSorting(status); // Vector of UnicodeStrings; owned by the vector.
+ preferenceSorting.setDeleter(uhash_deleteUnicodeString);
+ appendUnicodeSetToUVector(preferenceSorting, *initialLabels_, status);
+ preferenceSorting.sortWithUComparator(PreferenceComparator, &status, status);
+
+ // We now make a set of Labels.
+ // Some of the input may, however, be redundant.
+ // That is, we might have c, ch, d, where "ch" sorts just like "c", "h"
+ // So we make a pass through, filtering out those cases.
+ // TODO: filtering these out would seem to be at odds with the eventual goal
+ // of being able to split buckets that contain too many items.
+
+ UnicodeSet labelSet;
+ for (int32_t psIndex=0; psIndex<preferenceSorting.size(); psIndex++) {
+ UnicodeString item = *static_cast<const UnicodeString *>(preferenceSorting.elementAt(psIndex));
+ // TODO: Since preferenceSorting was originally populated from the contents of a UnicodeSet,
+ // is it even possible for duplicates to show up in this check?
+ if (labelSet.contains(item)) {
+ UnicodeSetIterator itemAlreadyInIter(labelSet);
+ while (itemAlreadyInIter.next()) {
+ const UnicodeString &itemAlreadyIn = itemAlreadyInIter.getString();
+ if (collatorPrimaryOnly_->compare(item, itemAlreadyIn) == 0) {
+ UnicodeSet *targets = static_cast<UnicodeSet *>(uhash_get(alreadyIn_, &itemAlreadyIn));
+ if (targets == NULL) {
+ // alreadyIn.put(itemAlreadyIn, targets = new LinkedHashSet<String>());
+ targets = new UnicodeSet();
+ uhash_put(alreadyIn_, itemAlreadyIn.clone(), targets, &status);
+ }
+ targets->add(item);
+ break;
+ }
+ }
+ } else if (item.moveIndex32(0, 1) < item.length() && // Label contains more than one code point.
+ collatorPrimaryOnly_->compare(item, separated(item)) == 0) {
+ noDistinctSorting_->add(item);
+ } else if (!ALPHABETIC->containsSome(item)) {
+ notAlphabetic_->add(item);
+ } else {
+ labelSet.add(item);
+ }
+ }
+
+ // Move the set of Labels from the set into a vector, and sort
+ // according to the collator.
+
+ appendUnicodeSetToUVector(*labels_, labelSet, status);
+ labels_->sortWithUComparator(sortCollateComparator, collatorPrimaryOnly_, status);
+
+ // if the result is still too large, cut down to maxLabelCount_ elements, by removing every nth element
+ // Implemented by copying the elements to be retained to a new UVector.
+
+ const int32_t size = labelSet.size() - 1;
+ if (size > maxLabelCount_) {
+ UVector *newLabels = new UVector(status);
+ newLabels->setDeleter(uhash_deleteUnicodeString);
+ int32_t count = 0;
+ int32_t old = -1;
+ for (int32_t srcIndex=0; srcIndex<labels_->size(); srcIndex++) {
+ const UnicodeString *str = static_cast<const UnicodeString *>(labels_->elementAt(srcIndex));
+ ++count;
+ const int32_t bump = count * maxLabelCount_ / size;
+ if (bump == old) {
+ // it.remove();
+ } else {
+ newLabels->addElement(str->clone(), status);
+ old = bump;
+ }
+ }
+ delete labels_;
+ labels_ = newLabels;
+ }
+
+ // We now know the list of labels.
+ // Create a corresponding list of buckets, one per label.
+
+ buildBucketList(status); // Corresponds to Java BucketList constructor.
+
+ // Bin the Records into the Buckets.
+ bucketRecords(status);
+
+ indexBuildRequired_ = FALSE;
+ resetBucketIterator(status);
+}
+
+//
+// buildBucketList() Corresponds to the BucketList constructor in the Java version.
+
+void AlphabeticIndex::buildBucketList(UErrorCode &status) {
+ UnicodeString labelStr = getUnderflowLabel();
+ Bucket *b = new Bucket(labelStr, *EMPTY_STRING, U_ALPHAINDEX_UNDERFLOW, status);
+ bucketList_->addElement(b, status);
+
+ // Build up the list, adding underflow, additions, overflow
+ // insert infix labels as needed, using \uFFFF.
+ const UnicodeString *last = static_cast<UnicodeString *>(labels_->elementAt(0));
+ b = new Bucket(*last, *last, U_ALPHAINDEX_NORMAL, status);
+ bucketList_->addElement(b, status);
+
+ UnicodeSet lastSet;
+ UnicodeSet set;
+ AlphabeticIndex::getScriptSet(lastSet, *last, status);
+ lastSet.removeAll(*IGNORE_SCRIPTS);
+
+ for (int i = 1; i < labels_->size(); ++i) {
+ UnicodeString *current = static_cast<UnicodeString *>(labels_->elementAt(i));
+ getScriptSet(set, *current, status);
+ set.removeAll(*IGNORE_SCRIPTS);
+ if (lastSet.containsNone(set)) {
+ // check for adjacent
+ const UnicodeString &overflowComparisonString = getOverflowComparisonString(*last, status);
+ if (collatorPrimaryOnly_->compare(overflowComparisonString, *current) < 0) {
+ labelStr = getInflowLabel();
+ b = new Bucket(labelStr, overflowComparisonString, U_ALPHAINDEX_INFLOW, status);
+ bucketList_->addElement(b, status);
+ i++;
+ lastSet = set;
+ }
+ }
+ b = new Bucket(*current, *current, U_ALPHAINDEX_NORMAL, status);
+ bucketList_->addElement(b, status);
+ last = current;
+ lastSet = set;
+ }
+ const UnicodeString &limitString = getOverflowComparisonString(*last, status);
+ b = new Bucket(getOverflowLabel(), limitString, U_ALPHAINDEX_OVERFLOW, status);
+ bucketList_->addElement(b, status);
+ // final overflow bucket
+}
+
+
+//
+// Place all of the raw input records into the correct bucket.
+//
+// Begin by sorting the input records; this lets us bin them in a single pass.
+//
+// Note on storage management: The input records are owned by the
+// inputRecords_ vector, and will (eventually) be auto-deleted by it.
+// The Bucket objects have pointers to the Record objects, but do not own them.
+//
+void AlphabeticIndex::bucketRecords(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ inputRecords_->sortWithUComparator(recordCompareFn, collator_, status);
+ U_ASSERT(bucketList_->size() > 0); // Should always have at least an overflow
+ // bucket, even if no user labels.
+ int32_t bucketIndex = 0;
+ Bucket *destBucket = static_cast<Bucket *>(bucketList_->elementAt(bucketIndex));
+ Bucket *nextBucket = NULL;
+ if (bucketIndex+1 < bucketList_->size()) {
+ nextBucket = static_cast<Bucket *>(bucketList_->elementAt(bucketIndex+1));
+ }
+ int32_t recordIndex = 0;
+ Record *r = static_cast<Record *>(inputRecords_->elementAt(recordIndex));
+ while (recordIndex < inputRecords_->size()) {
+ if (nextBucket == NULL ||
+ collatorPrimaryOnly_->compare(r->sortingName_, nextBucket->lowerBoundary_) < 0) {
+ // Record goes in current bucket. Advance to next record,
+ // stay on current bucket.
+ destBucket->records_->addElement(r, status);
+ ++recordIndex;
+ r = static_cast<Record *>(inputRecords_->elementAt(recordIndex));
+ } else {
+ // Advance to the next bucket, stay on current record.
+ bucketIndex++;
+ destBucket = nextBucket;
+ if (bucketIndex+1 < bucketList_->size()) {
+ nextBucket = static_cast<Bucket *>(bucketList_->elementAt(bucketIndex+1));
+ } else {
+ nextBucket = NULL;
+ }
+ U_ASSERT(destBucket != NULL);
+ }
+ }
+
+}
+
+
+void AlphabeticIndex::getIndexExemplars(UnicodeSet &dest, const Locale &locale, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ LocalULocaleDataPointer uld(ulocdata_open(locale.getName(), &status));
+ UnicodeSet exemplars;
+ ulocdata_getExemplarSet(uld.getAlias(), exemplars.toUSet(), 0, ULOCDATA_ES_INDEX, &status);
+ if (U_SUCCESS(status)) {
+ dest.addAll(exemplars);
+ return;
+ }
+ status = U_ZERO_ERROR; // Clear out U_MISSING_RESOURCE_ERROR
+
+ // Locale data did not include explicit Index characters.
+ // Synthesize a set of them from the locale's standard exemplar characters.
+
+ ulocdata_getExemplarSet(uld.getAlias(), exemplars.toUSet(), 0, ULOCDATA_ES_STANDARD, &status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Upper-case any that aren't already so.
+ // (We only do this for synthesized index characters.)
+
+ UnicodeSetIterator it(exemplars);
+ UnicodeString upperC;
+ UnicodeSet lowersToRemove;
+ UnicodeSet uppersToAdd;
+ while (it.next()) {
+ const UnicodeString &exemplarC = it.getString();
+ upperC = exemplarC;
+ upperC.toUpper(locale);
+ if (exemplarC != upperC) {
+ lowersToRemove.add(exemplarC);
+ uppersToAdd.add(upperC);
+ }
+ }
+ exemplars.removeAll(lowersToRemove);
+ exemplars.addAll(uppersToAdd);
+
+ // get the exemplars, and handle special cases
+
+ // question: should we add auxiliary exemplars?
+ if (exemplars.containsSome(*CORE_LATIN)) {
+ exemplars.addAll(*CORE_LATIN);
+ }
+ if (exemplars.containsSome(*HANGUL)) {
+ // cut down to small list
+ UnicodeSet BLOCK_HANGUL_SYLLABLES(UNICODE_STRING_SIMPLE("[:block=hangul_syllables:]"), status);
+ exemplars.removeAll(BLOCK_HANGUL_SYLLABLES);
+ exemplars.addAll(*HANGUL);
+ }
+ if (exemplars.containsSome(*ETHIOPIC)) {
+ // cut down to small list
+ // make use of the fact that Ethiopic is allocated in 8's, where
+ // the base is 0 mod 8.
+ UnicodeSetIterator it(*ETHIOPIC);
+ while (it.next() && !it.isString()) {
+ if ((it.getCodepoint() & 0x7) != 0) {
+ exemplars.remove(it.getCodepoint());
+ }
+ }
+ }
+ dest.addAll(exemplars);
+}
+
+
+/*
+ * Return the string with interspersed CGJs. Input must have more than 2 codepoints.
+ */
+static const UChar32 CGJ = (UChar)0x034F;
+UnicodeString AlphabeticIndex::separated(const UnicodeString &item) {
+ UnicodeString result;
+ if (item.length() == 0) {
+ return result;
+ }
+ int32_t i = 0;
+ for (;;) {
+ UChar32 cp = item.char32At(i);
+ result.append(cp);
+ i = item.moveIndex32(i, 1);
+ if (i >= item.length()) {
+ break;
+ }
+ result.append(CGJ);
+ }
+ return result;
+}
+
+
+UBool AlphabeticIndex::operator==(const AlphabeticIndex& /* other */) const {
+ return FALSE;
+}
+
+
+UBool AlphabeticIndex::operator!=(const AlphabeticIndex& /* other */) const {
+ return FALSE;
+}
+
+
+const RuleBasedCollator &AlphabeticIndex::getCollator() const {
+ // There are no known non-RuleBasedCollator collators, and none ever expected.
+ // But, in case that changes, better a null pointer than a wrong type.
+ return *dynamic_cast<RuleBasedCollator *>(collator_);
+}
+
+
+const UnicodeString &AlphabeticIndex::getInflowLabel() const {
+ return inflowLabel_;
+}
+
+const UnicodeString &AlphabeticIndex::getOverflowLabel() const {
+ return overflowLabel_;
+}
+
+
+const UnicodeString &AlphabeticIndex::getUnderflowLabel() const {
+ return underflowLabel_;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::setInflowLabel(const UnicodeString &label, UErrorCode &/*status*/) {
+ inflowLabel_ = label;
+ indexBuildRequired_ = TRUE;
+ return *this;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::setOverflowLabel(const UnicodeString &label, UErrorCode &/*status*/) {
+ overflowLabel_ = label;
+ indexBuildRequired_ = TRUE;
+ return *this;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::setUnderflowLabel(const UnicodeString &label, UErrorCode &/*status*/) {
+ underflowLabel_ = label;
+ indexBuildRequired_ = TRUE;
+ return *this;
+}
+
+
+int32_t AlphabeticIndex::getMaxLabelCount() const {
+ return maxLabelCount_;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::setMaxLabelCount(int32_t maxLabelCount, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (maxLabelCount <= 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ maxLabelCount_ = maxLabelCount;
+ if (maxLabelCount < bucketList_->size()) {
+ indexBuildRequired_ = TRUE;
+ }
+ return *this;
+}
+
+
+const UnicodeString &AlphabeticIndex::getOverflowComparisonString(const UnicodeString &lowerLimit, UErrorCode &/*status*/) {
+ for (int32_t i=0; i<firstScriptCharacters_->size(); i++) {
+ const UnicodeString *s =
+ static_cast<const UnicodeString *>(firstScriptCharacters_->elementAt(i));
+ if (collator_->compare(*s, lowerLimit) > 0) {
+ return *s;
+ }
+ }
+ return *EMPTY_STRING;
+}
+
+UnicodeSet *AlphabeticIndex::getScriptSet(UnicodeSet &dest, const UnicodeString &codePoint, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return &dest;
+ }
+ UChar32 cp = codePoint.char32At(0);
+ UScriptCode scriptCode = uscript_getScript(cp, &status);
+ dest.applyIntPropertyValue(UCHAR_SCRIPT, scriptCode, status);
+ return &dest;
+}
+
+//
+// init() - Common code for constructors.
+//
+
+void AlphabeticIndex::init(UErrorCode &status) {
+ // Initialize statics if needed.
+ AlphabeticIndex::staticInit(status);
+
+ // Put the object into a known state so that the destructor will function.
+
+ alreadyIn_ = NULL;
+ bucketList_ = NULL;
+ collator_ = NULL;
+ collatorPrimaryOnly_ = NULL;
+ currentBucket_ = NULL;
+ firstScriptCharacters_ = NULL;
+ initialLabels_ = NULL;
+ indexBuildRequired_ = TRUE;
+ inputRecords_ = NULL;
+ itemsIterIndex_ = 0;
+ labels_ = NULL;
+ labelsIterIndex_ = 0;
+ maxLabelCount_ = 99;
+ noDistinctSorting_ = NULL;
+ notAlphabetic_ = NULL;
+ recordCounter_ = 0;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ alreadyIn_ = uhash_open(uhash_hashUnicodeString, // Key Hash,
+ uhash_compareUnicodeString, // key Comparator,
+ NULL, // value Comparator
+ &status);
+ uhash_setKeyDeleter(alreadyIn_, uhash_deleteUnicodeString);
+ uhash_setValueDeleter(alreadyIn_, uhash_deleteUnicodeSet);
+
+ bucketList_ = new UVector(status);
+ bucketList_->setDeleter(alphaIndex_deleteBucket);
+ labels_ = new UVector(status);
+ labels_->setDeleter(uhash_deleteUnicodeString);
+ labels_->setComparer(uhash_compareUnicodeString);
+ inputRecords_ = new UVector(status);
+ inputRecords_->setDeleter(alphaIndex_deleteRecord);
+
+ noDistinctSorting_ = new UnicodeSet();
+ notAlphabetic_ = new UnicodeSet();
+ initialLabels_ = new UnicodeSet();
+
+ inflowLabel_.remove();
+ inflowLabel_.append((UChar)0x2026); // Ellipsis
+ overflowLabel_ = inflowLabel_;
+ underflowLabel_ = inflowLabel_;
+
+ // TODO: check for memory allocation failures.
+}
+
+
+static UBool indexCharactersAreInitialized = FALSE;
+
+// Index Characters Clean up function. Delete statically allocated constant stuff.
+U_CDECL_BEGIN
+static UBool U_CALLCONV indexCharacters_cleanup(void) {
+ AlphabeticIndex::staticCleanup();
+ return TRUE;
+}
+U_CDECL_END
+
+void AlphabeticIndex::staticCleanup() {
+ delete ALPHABETIC;
+ ALPHABETIC = NULL;
+ delete HANGUL;
+ HANGUL = NULL;
+ delete ETHIOPIC;
+ ETHIOPIC = NULL;
+ delete CORE_LATIN;
+ CORE_LATIN = NULL;
+ delete IGNORE_SCRIPTS;
+ IGNORE_SCRIPTS = NULL;
+ delete TO_TRY;
+ TO_TRY = NULL;
+ delete UNIHAN;
+ UNIHAN = NULL;
+ delete EMPTY_STRING;
+ EMPTY_STRING = NULL;
+ nfkdNormalizer = NULL; // ref to a singleton. Do not delete.
+ indexCharactersAreInitialized = FALSE;
+}
+
+
+UnicodeSet *AlphabeticIndex::ALPHABETIC;
+UnicodeSet *AlphabeticIndex::HANGUL;
+UnicodeSet *AlphabeticIndex::ETHIOPIC;
+UnicodeSet *AlphabeticIndex::CORE_LATIN;
+UnicodeSet *AlphabeticIndex::IGNORE_SCRIPTS;
+UnicodeSet *AlphabeticIndex::TO_TRY;
+UnicodeSet *AlphabeticIndex::UNIHAN;
+const UnicodeString *AlphabeticIndex::EMPTY_STRING;
+
+//
+// staticInit() One-time initialization of constants.
+// Thread safe. Called from constructors.
+// Mutex overhead is not a concern. AlphabeticIndex constructors are
+// sufficiently heavy that the cost of the mutex check is not significant.
+
+void AlphabeticIndex::staticInit(UErrorCode &status) {
+ static UMTX IndexCharsInitMutex;
+
+ Mutex mutex(&IndexCharsInitMutex);
+ if (indexCharactersAreInitialized || U_FAILURE(status)) {
+ return;
+ }
+ UBool finishedInit = FALSE;
+
+ {
+ UnicodeString alphaString = UNICODE_STRING_SIMPLE("[[:alphabetic:]-[:mark:]]");
+ ALPHABETIC = new UnicodeSet(alphaString, status);
+ if (ALPHABETIC == NULL) {
+ goto err;
+ }
+
+ HANGUL = new UnicodeSet();
+ HANGUL->add(0xAC00).add(0xB098).add(0xB2E4).add(0xB77C).add(0xB9C8).add(0xBC14).add(0xC0AC).
+ add(0xC544).add(0xC790).add(0xCC28).add(0xCE74).add(0xD0C0).add(0xD30C).add(0xD558);
+ if (HANGUL== NULL) {
+ goto err;
+ }
+
+
+ UnicodeString EthiopicStr = UNICODE_STRING_SIMPLE("[[:Block=Ethiopic:]&[:Script=Ethiopic:]]");
+ ETHIOPIC = new UnicodeSet(EthiopicStr, status);
+ if (ETHIOPIC == NULL) {
+ goto err;
+ }
+
+ CORE_LATIN = new UnicodeSet((UChar32)0x61, (UChar32)0x7a); // ('a', 'z');
+ if (CORE_LATIN == NULL) {
+ goto err;
+ }
+
+ UnicodeString IgnoreStr= UNICODE_STRING_SIMPLE(
+ "[[:sc=Common:][:sc=inherited:][:script=Unknown:][:script=braille:]]");
+ IGNORE_SCRIPTS = new UnicodeSet(IgnoreStr, status);
+ IGNORE_SCRIPTS->freeze();
+ if (IGNORE_SCRIPTS == NULL) {
+ goto err;
+ }
+
+ UnicodeString nfcqcStr = UNICODE_STRING_SIMPLE("[:^nfcqc=no:]");
+ TO_TRY = new UnicodeSet(nfcqcStr, status);
+ if (TO_TRY == NULL) {
+ goto err;
+ }
+
+ UnicodeString unihanStr = UNICODE_STRING_SIMPLE("[:script=Hani:]");
+ UNIHAN = new UnicodeSet(unihanStr, status);
+ if (UNIHAN == NULL) {
+ goto err;
+ }
+
+ EMPTY_STRING = new UnicodeString();
+
+ nfkdNormalizer = Normalizer2::getInstance(NULL, "nfkc", UNORM2_DECOMPOSE, status);
+ if (nfkdNormalizer == NULL) {
+ goto err;
+ }
+ }
+ finishedInit = TRUE;
+
+ err:
+ if (!finishedInit && U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ indexCharacters_cleanup();
+ return;
+ }
+ ucln_i18n_registerCleanup(UCLN_I18N_INDEX_CHARACTERS, indexCharacters_cleanup);
+ indexCharactersAreInitialized = TRUE;
+}
+
+
+//
+// Comparison function for UVector<UnicodeString *> sorting with a collator.
+//
+static int32_t U_CALLCONV
+sortCollateComparator(const void *context, const void *left, const void *right) {
+ const UHashTok *leftTok = static_cast<const UHashTok *>(left);
+ const UHashTok *rightTok = static_cast<const UHashTok *>(right);
+ const UnicodeString *leftString = static_cast<const UnicodeString *>(leftTok->pointer);
+ const UnicodeString *rightString = static_cast<const UnicodeString *>(rightTok->pointer);
+ const Collator *col = static_cast<const Collator *>(context);
+
+ if (leftString == rightString) {
+ // Catches case where both are NULL
+ return 0;
+ }
+ if (leftString == NULL) {
+ return 1;
+ };
+ if (rightString == NULL) {
+ return -1;
+ }
+ Collator::EComparisonResult r = col->compare(*leftString, *rightString);
+ return (int32_t) r;
+}
+
+//
+// Comparison function for UVector<Record *> sorting with a collator.
+//
+static int32_t U_CALLCONV
+recordCompareFn(const void *context, const void *left, const void *right) {
+ const UHashTok *leftTok = static_cast<const UHashTok *>(left);
+ const UHashTok *rightTok = static_cast<const UHashTok *>(right);
+ const AlphabeticIndex::Record *leftRec = static_cast<const AlphabeticIndex::Record *>(leftTok->pointer);
+ const AlphabeticIndex::Record *rightRec = static_cast<const AlphabeticIndex::Record *>(rightTok->pointer);
+ const Collator *col = static_cast<const Collator *>(context);
+
+ Collator::EComparisonResult r = col->compare(leftRec->sortingName_, rightRec->sortingName_);
+ if (r == Collator::EQUAL) {
+ if (leftRec->serialNumber_ < rightRec->serialNumber_) {
+ r = Collator::LESS;
+ } else if (leftRec->serialNumber_ > rightRec->serialNumber_) {
+ r = Collator::GREATER;
+ }
+ }
+ return (int32_t) r;
+}
+
+
+#if 0
+//
+// First characters in scripts.
+// Create a UVector whose contents are pointers to UnicodeStrings for the First Characters in each script.
+// The vector is sorted according to this index's collation.
+//
+// This code is too slow to use, so for now hard code the data.
+// Hard coded implementation is follows.
+//
+UVector *AlphabeticIndex::firstStringsInScript(Collator *ruleBasedCollator, UErrorCode &status) {
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UnicodeString results[USCRIPT_CODE_LIMIT];
+ UnicodeString LOWER_A = UNICODE_STRING_SIMPLE("a");
+
+ UnicodeSetIterator siter(*TO_TRY);
+ while (siter.next()) {
+ const UnicodeString &current = siter.getString();
+ Collator::EComparisonResult r = ruleBasedCollator->compare(current, LOWER_A);
+ if (r < 0) { // TODO fix; we only want "real" script characters, not
+ // symbols.
+ continue;
+ }
+
+ int script = uscript_getScript(current.char32At(0), &status);
+ if (results[script].length() == 0) {
+ results[script] = current;
+ }
+ else if (ruleBasedCollator->compare(current, results[script]) < 0) {
+ results[script] = current;
+ }
+ }
+
+ UnicodeSet extras;
+ UnicodeSet expansions;
+ RuleBasedCollator *rbc = dynamic_cast<RuleBasedCollator *>(ruleBasedCollator);
+ const UCollator *uRuleBasedCollator = rbc->getUCollator();
+ ucol_getContractionsAndExpansions(uRuleBasedCollator, extras.toUSet(), expansions.toUSet(), true, &status);
+ extras.addAll(expansions).removeAll(*TO_TRY);
+ if (extras.size() != 0) {
+ const Normalizer2 *normalizer = Normalizer2::getInstance(NULL, "nfkc", UNORM2_COMPOSE, status);
+ UnicodeSetIterator extrasIter(extras);
+ while (extrasIter.next()) {
+ const UnicodeString &current = extrasIter.next();
+ if (!TO_TRY->containsAll(current))
+ continue;
+ if (!normalizer->isNormalized(current, status) ||
+ ruleBasedCollator->compare(current, LOWER_A) < 0) {
+ continue;
+ }
+ int script = uscript_getScript(current.char32At(0), &status);
+ if (results[script].length() == 0) {
+ results[script] = current;
+ } else if (ruleBasedCollator->compare(current, results[script]) < 0) {
+ results[script] = current;
+ }
+ }
+ }
+
+ UVector *dest = new UVector(status);
+ dest->setDeleter(uhash_deleteUnicodeString);
+ for (uint32_t i = 0; i < sizeof(results) / sizeof(results[0]); ++i) {
+ if (results[i].length() > 0) {
+ dest->addElement(results[i].clone(), status);
+ }
+ }
+ dest->sortWithUComparator(sortCollateComparator, ruleBasedCollator, status);
+ return dest;
+}
+#endif
+
+
+//
+// First characters in scripts.
+// Create a UVector whose contents are pointers to UnicodeStrings for the First Characters in each script.
+// The vector is sorted according to this index's collation.
+//
+// It takes too much time to compute this from character properties, so hard code it for now.
+// Character constants copied from corresponding declaration in ICU4J.
+
+static UChar HACK_FIRST_CHARS_IN_SCRIPTS[] = { 0x61, 0, 0x03B1, 0,
+ 0x2C81, 0, 0x0430, 0, 0x2C30, 0, 0x10D0, 0, 0x0561, 0, 0x05D0, 0, 0xD802, 0xDD00, 0, 0x0800, 0, 0x0621, 0, 0x0710, 0,
+ 0x0780, 0, 0x07CA, 0, 0x2D30, 0, 0x1200, 0, 0x0950, 0, 0x0985, 0, 0x0A74, 0, 0x0AD0, 0, 0x0B05, 0, 0x0BD0, 0,
+ 0x0C05, 0, 0x0C85, 0, 0x0D05, 0, 0x0D85, 0, 0xABC0, 0, 0xA800, 0, 0xA882, 0, 0xD804, 0xDC83, 0, 0x1B83, 0,
+ 0xD802, 0xDE00, 0, 0x0E01, 0, 0x0E81, 0, 0xAA80, 0, 0x0F40, 0, 0x1C00, 0, 0xA840, 0, 0x1900, 0, 0x1700, 0, 0x1720, 0,
+ 0x1740, 0, 0x1760, 0, 0x1A00, 0, 0xA930, 0, 0xA90A, 0, 0x1000, 0, 0x1780, 0, 0x1950, 0, 0x1980, 0, 0x1A20, 0,
+ 0xAA00, 0, 0x1B05, 0, 0xA984, 0, 0x1880, 0, 0x1C5A, 0, 0x13A0, 0, 0x1401, 0, 0x1681, 0, 0x16A0, 0, 0xD803, 0xDC00, 0,
+ 0xA500, 0, 0xA6A0, 0, 0x1100, 0, 0x3041, 0, 0x30A1, 0, 0x3105, 0, 0xA000, 0, 0xA4F8, 0, 0xD800, 0xDE80, 0,
+ 0xD800, 0xDEA0, 0, 0xD802, 0xDD20, 0, 0xD800, 0xDF00, 0, 0xD800, 0xDF30, 0, 0xD801, 0xDC28, 0, 0xD801, 0xDC50, 0,
+ 0xD801, 0xDC80, 0, 0xD800, 0xDC00, 0, 0xD802, 0xDC00, 0, 0xD802, 0xDE60, 0, 0xD802, 0xDF00, 0, 0xD802, 0xDC40, 0,
+ 0xD802, 0xDF40, 0, 0xD802, 0xDF60, 0, 0xD800, 0xDF80, 0, 0xD800, 0xDFA0, 0, 0xD808, 0xDC00, 0, 0xD80C, 0xDC00, 0, 0x4E00, 0 };
+
+UVector *AlphabeticIndex::firstStringsInScript(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UVector *dest = new UVector(status);
+ if (dest == NULL && U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ dest->setDeleter(uhash_deleteUnicodeString);
+ const UChar *src = HACK_FIRST_CHARS_IN_SCRIPTS;
+ const UChar *limit = src + sizeof(HACK_FIRST_CHARS_IN_SCRIPTS) / sizeof(HACK_FIRST_CHARS_IN_SCRIPTS[0]);
+ do {
+ if (U_FAILURE(status)) {
+ return dest;
+ }
+ UnicodeString *str = new UnicodeString(src, -1);
+ if (str == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ dest->addElement(str, status);
+ src += str->length() + 1;
+ } while (src < limit);
+ dest->sortWithUComparator(sortCollateComparator, collator_, status);
+ return dest;
+}
+
+
+AlphabeticIndex::ELangType AlphabeticIndex::langTypeFromLocale(const Locale &loc) {
+ const char *lang = loc.getLanguage();
+ if (uprv_strcmp(lang, "zh") != 0) {
+ return kNormal;
+ }
+ const char *script = loc.getScript();
+ if (uprv_strcmp(script, "Hant") == 0) {
+ return kTraditional;
+ }
+ const char *country = loc.getCountry();
+ if (uprv_strcmp(country, "TW") == 0) {
+ return kTraditional;
+ }
+ return kSimplified;
+}
+
+
+//
+// Pinyin Hacks. Direct port from Java.
+//
+
+static const UChar32 probeCharInLong = 0x28EAD;
+
+
+static const UChar PINYIN_LOWER_BOUNDS_SHORT[] = { // "\u0101bcd\u0113fghjkl\u1E3F\u0144\u014Dpqrstwxyz"
+ 0x0101, 0x62, 0x63, 0x64, 0x0113, 0x66, 0x67, 0x68, 0x6A, 0x6B, /*l*/0x6C, 0x1E3F, 0x0144, 0x014D,
+ /*p*/0x70, 0x71, 0x72, 0x73, 0x74, /*w*/0x77, 0x78, 0x79, 0x7A};
+
+
+// Pinyin lookup tables copied, pasted (and reformatted) from the ICU4J code.
+
+AlphabeticIndex::PinyinLookup AlphabeticIndex::HACK_PINYIN_LOOKUP_SHORT = {
+ {(UChar)0, (UChar)0, (UChar)0}, // A
+ {(UChar)0x516B, (UChar)0, (UChar)0}, // B
+ {(UChar)0x5693, (UChar)0, (UChar)0}, // C
+ {(UChar)0x5491, (UChar)0, (UChar)0}, // D
+ {(UChar)0x59B8, (UChar)0, (UChar)0}, // E
+ {(UChar)0x53D1, (UChar)0, (UChar)0}, // F
+ {(UChar)0x65EE, (UChar)0, (UChar)0}, // G
+ {(UChar)0x54C8, (UChar)0, (UChar)0}, // H
+ {(UChar)0x4E0C, (UChar)0, (UChar)0}, // J
+ {(UChar)0x5494, (UChar)0, (UChar)0}, // K
+ {(UChar)0x5783, (UChar)0, (UChar)0}, // L
+ {(UChar)0x5452, (UChar)0, (UChar)0}, // M
+ {(UChar)0x5514, (UChar)0, (UChar)0}, // N
+ {(UChar)0x5594, (UChar)0, (UChar)0}, // O
+ {(UChar)0x5991, (UChar)0, (UChar)0}, // P
+ {(UChar)0x4E03, (UChar)0, (UChar)0}, // Q
+ {(UChar)0x513F, (UChar)0, (UChar)0}, // R
+ {(UChar)0x4EE8, (UChar)0, (UChar)0}, // S
+ {(UChar)0x4ED6, (UChar)0, (UChar)0}, // T
+ {(UChar)0x7A75, (UChar)0, (UChar)0}, // W
+ {(UChar)0x5915, (UChar)0, (UChar)0}, // X
+ {(UChar)0x4E2B, (UChar)0, (UChar)0}, // Y
+ {(UChar)0x5E00, (UChar)0, (UChar)0}, // Z
+ {(UChar)0xFFFF, (UChar)0, (UChar)0}, // mark end of array
+ };
+
+static const UChar PINYIN_LOWER_BOUNDS_LONG[] = { // "\u0101bcd\u0113fghjkl\u1E3F\u0144\u014Dpqrstwxyz";
+ 0x0101, 0x62, 0x63, 0x64, 0x0113, 0x66, 0x67, 0x68, 0x6A, 0x6B, /*l*/0x6C, 0x1E3F, 0x0144, 0x014D,
+ /*p*/0x70, 0x71, 0x72, 0x73, 0x74, /*w*/0x77, 0x78, 0x79, 0x7A};
+
+AlphabeticIndex::PinyinLookup AlphabeticIndex::HACK_PINYIN_LOOKUP_LONG = {
+ {(UChar)0, (UChar)0, (UChar)0}, // A
+ {(UChar)0x516B, (UChar)0, (UChar)0}, // b
+ {(UChar)0xD863, (UChar)0xDEAD, (UChar)0}, // c
+ {(UChar)0xD844, (UChar)0xDE51, (UChar)0}, // d
+ {(UChar)0x59B8, (UChar)0, (UChar)0}, // e
+ {(UChar)0x53D1, (UChar)0, (UChar)0}, // f
+ {(UChar)0xD844, (UChar)0xDE45, (UChar)0}, // g
+ {(UChar)0x54C8, (UChar)0, (UChar)0}, // h
+ {(UChar)0x4E0C, (UChar)0, (UChar)0}, // j
+ {(UChar)0x5494, (UChar)0, (UChar)0}, // k
+ {(UChar)0x3547, (UChar)0, (UChar)0}, // l
+ {(UChar)0x5452, (UChar)0, (UChar)0}, // m
+ {(UChar)0x5514, (UChar)0, (UChar)0}, // n
+ {(UChar)0x5594, (UChar)0, (UChar)0}, // o
+ {(UChar)0xD84F, (UChar)0xDC7A, (UChar)0}, // p
+ {(UChar)0x4E03, (UChar)0, (UChar)0}, // q
+ {(UChar)0x513F, (UChar)0, (UChar)0}, // r
+ {(UChar)0x4EE8, (UChar)0, (UChar)0}, // s
+ {(UChar)0x4ED6, (UChar)0, (UChar)0}, // t
+ {(UChar)0x7A75, (UChar)0, (UChar)0}, // w
+ {(UChar)0x5915, (UChar)0, (UChar)0}, // x
+ {(UChar)0x4E2B, (UChar)0, (UChar)0}, // y
+ {(UChar)0x5E00, (UChar)0, (UChar)0}, // z
+ {(UChar)0xFFFF, (UChar)0, (UChar)0}, // mark end of array
+ };
+
+
+//
+// Probe the collation data, and decide which Pinyin tables should be used
+//
+// ICU can be built with a choice between two Chinese collations.
+// The hack Pinyin tables to use depend on which one is in use.
+// We can assume that any given copy of ICU will have only one of the collations available,
+// and that there is no way, in a given process, to create two alphabetic indexes using
+// different Chinese collations. Which means the probe can be done once
+// and the results cached.
+//
+// This whole arrangement is temporary.
+//
+AlphabeticIndex::PinyinLookup *AlphabeticIndex::HACK_PINYIN_LOOKUP = NULL;
+const UChar *AlphabeticIndex::PINYIN_LOWER_BOUNDS = NULL;
+
+void AlphabeticIndex::initPinyinBounds(const Collator *col, UErrorCode &status) {
+ {
+ Mutex m;
+ if (PINYIN_LOWER_BOUNDS != NULL) {
+ return;
+ }
+ }
+ UnicodeSet *colSet = col->getTailoredSet(status);
+ if (U_FAILURE(status) || colSet == NULL) {
+ delete colSet;
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return;
+ }
+ UBool useLongTables = colSet->contains(probeCharInLong);
+ delete colSet;
+ {
+ Mutex m;
+ if (useLongTables) {
+ PINYIN_LOWER_BOUNDS = PINYIN_LOWER_BOUNDS_LONG;
+ HACK_PINYIN_LOOKUP = &HACK_PINYIN_LOOKUP_LONG;
+ } else {
+ PINYIN_LOWER_BOUNDS = PINYIN_LOWER_BOUNDS_SHORT;
+ HACK_PINYIN_LOOKUP = &HACK_PINYIN_LOOKUP_SHORT;
+ }
+ }
+}
+
+// Pinyin Hack:
+// Modify a Chinese name by prepending a Latin letter. The modified name is used
+// when putting records (names) into buckets, to put the name under a Latin index heading.
+
+void AlphabeticIndex::hackName(UnicodeString &dest, const UnicodeString &name, const Collator *col) {
+
+ if (langType_ != kSimplified || !UNIHAN->contains(name.char32At(0))) {
+ dest = name;
+ return;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ initPinyinBounds(col, status);
+ if (U_FAILURE(status)) {
+ dest = name;
+ return;
+ }
+ // TODO: use binary search
+ int index;
+ for (index=0; ; index++) {
+ if ((*HACK_PINYIN_LOOKUP)[index][0] == (UChar)0xffff) {
+ index--;
+ break;
+ }
+ int32_t compareResult = col->compare(name, (*HACK_PINYIN_LOOKUP)[index]);
+ if (compareResult < 0) {
+ index--;
+ }
+ if (compareResult <= 0) {
+ break;
+ }
+ }
+ UChar c = PINYIN_LOWER_BOUNDS[index];
+ dest.setTo(c);
+ dest.append(name);
+ return;
+}
+
+
+
+/**
+ * Comparator that returns "better" items first, where shorter NFKD is better, and otherwise NFKD binary order is
+ * better, and otherwise binary order is better.
+ *
+ * For use with array sort or UVector.
+ * @param context A UErrorCode pointer.
+ * @param left A UHashTok pointer, which must refer to a UnicodeString *
+ * @param right A UHashTok pointer, which must refer to a UnicodeString *
+ */
+
+static int32_t U_CALLCONV
+PreferenceComparator(const void *context, const void *left, const void *right) {
+ const UHashTok *leftTok = static_cast<const UHashTok *>(left);
+ const UHashTok *rightTok = static_cast<const UHashTok *>(right);
+ const UnicodeString *s1 = static_cast<const UnicodeString *>(leftTok->pointer);
+ const UnicodeString *s2 = static_cast<const UnicodeString *>(rightTok->pointer);
+ UErrorCode &status = *(UErrorCode *)(context); // Cast off both static and const.
+ if (s1 == s2) {
+ return 0;
+ }
+
+ UnicodeString n1 = nfkdNormalizer->normalize(*s1, status);
+ UnicodeString n2 = nfkdNormalizer->normalize(*s2, status);
+ int32_t result = n1.length() - n2.length();
+ if (result != 0) {
+ return result;
+ }
+
+ result = n1.compareCodePointOrder(n2);
+ if (result != 0) {
+ return result;
+ }
+ return s1->compareCodePointOrder(*s2);
+}
+
+
+//
+// Constructor & Destructor for AlphabeticIndex::Record
+//
+// Records are internal only, instances are not directly surfaced in the public API.
+// This class is mostly struct-like, with all public fields.
+
+AlphabeticIndex::Record::Record(AlphabeticIndex *alphaIndex, const UnicodeString &name, const void *data):
+ alphaIndex_(alphaIndex), name_(name), data_(data)
+{
+ UnicodeString prefixedName;
+ alphaIndex->hackName(sortingName_, name_, alphaIndex->collatorPrimaryOnly_);
+ serialNumber_ = ++alphaIndex->recordCounter_;
+}
+
+AlphabeticIndex::Record::~Record() {
+}
+
+
+AlphabeticIndex & AlphabeticIndex::addRecord(const UnicodeString &name, const void *data, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ Record *r = new Record(this, name, data);
+ inputRecords_->addElement(r, status);
+ indexBuildRequired_ = TRUE;
+ //std::string ss;
+ //std::string ss2;
+ //std::cout << "added record: name = \"" << r->name_.toUTF8String(ss) << "\"" <<
+ // " sortingName = \"" << r->sortingName_.toUTF8String(ss2) << "\"" << std::endl;
+ return *this;
+}
+
+
+AlphabeticIndex &AlphabeticIndex::clearRecords(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ inputRecords_->removeAllElements();
+ indexBuildRequired_ = TRUE;
+ return *this;
+}
+
+
+int32_t AlphabeticIndex::getBucketIndex(const UnicodeString &name, UErrorCode &status) {
+ buildIndex(status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ // For simplified Chinese prepend a prefix to the name.
+ // For non-Chinese locales or non-Chinese names, the name is not modified.
+
+ UnicodeString prefixedName;
+ hackName(prefixedName, name, collatorPrimaryOnly_);
+
+ // TODO: use a binary search.
+ for (int32_t i = 0; i < bucketList_->size(); ++i) {
+ Bucket *bucket = static_cast<Bucket *>(bucketList_->elementAt(i));
+ Collator::EComparisonResult comp = collatorPrimaryOnly_->compare(prefixedName, bucket->lowerBoundary_);
+ if (comp < 0) {
+ return i - 1;
+ }
+ }
+ // Loop runs until we find the bucket following the one that would hold prefixedName.
+ // If the prefixedName belongs in the last bucket the loop will drop out the bottom rather
+ // than returning from the middle.
+
+ return bucketList_->size() - 1;
+}
+
+
+int32_t AlphabeticIndex::getBucketIndex() const {
+ return labelsIterIndex_;
+}
+
+
+UBool AlphabeticIndex::nextBucket(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (indexBuildRequired_ && currentBucket_ != NULL) {
+ status = U_ENUM_OUT_OF_SYNC_ERROR;
+ return FALSE;
+ }
+ buildIndex(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ ++labelsIterIndex_;
+ if (labelsIterIndex_ >= bucketList_->size()) {
+ labelsIterIndex_ = bucketList_->size();
+ return FALSE;
+ }
+ currentBucket_ = static_cast<Bucket *>(bucketList_->elementAt(labelsIterIndex_));
+ resetRecordIterator();
+ return TRUE;
+}
+
+const UnicodeString &AlphabeticIndex::getBucketLabel() const {
+ if (currentBucket_ != NULL) {
+ return currentBucket_->label_;
+ } else {
+ return *EMPTY_STRING;
+ }
+}
+
+
+UAlphabeticIndexLabelType AlphabeticIndex::getBucketLabelType() const {
+ if (currentBucket_ != NULL) {
+ return currentBucket_->labelType_;
+ } else {
+ return U_ALPHAINDEX_NORMAL;
+ }
+}
+
+
+int32_t AlphabeticIndex::getBucketRecordCount() const {
+ if (currentBucket_ != NULL) {
+ return currentBucket_->records_->size();
+ } else {
+ return 0;
+ }
+}
+
+
+AlphabeticIndex &AlphabeticIndex::resetBucketIterator(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ buildIndex(status);
+ labelsIterIndex_ = -1;
+ currentBucket_ = NULL;
+ return *this;
+}
+
+
+UBool AlphabeticIndex::nextRecord(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (currentBucket_ == NULL) {
+ // We are trying to iterate over the items in a bucket, but there is no
+ // current bucket from the enumeration of buckets.
+ status = U_INVALID_STATE_ERROR;
+ return FALSE;
+ }
+ if (indexBuildRequired_) {
+ status = U_ENUM_OUT_OF_SYNC_ERROR;
+ return FALSE;
+ }
+ ++itemsIterIndex_;
+ if (itemsIterIndex_ >= currentBucket_->records_->size()) {
+ itemsIterIndex_ = currentBucket_->records_->size();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+const UnicodeString &AlphabeticIndex::getRecordName() const {
+ const UnicodeString *retStr = EMPTY_STRING;
+ if (currentBucket_ != NULL &&
+ itemsIterIndex_ >= 0 &&
+ itemsIterIndex_ < currentBucket_->records_->size()) {
+ Record *item = static_cast<Record *>(currentBucket_->records_->elementAt(itemsIterIndex_));
+ retStr = &item->name_;
+ }
+ return *retStr;
+}
+
+const void *AlphabeticIndex::getRecordData() const {
+ const void *retPtr = NULL;
+ if (currentBucket_ != NULL &&
+ itemsIterIndex_ >= 0 &&
+ itemsIterIndex_ < currentBucket_->records_->size()) {
+ Record *item = static_cast<Record *>(currentBucket_->records_->elementAt(itemsIterIndex_));
+ retPtr = item->data_;
+ }
+ return retPtr;
+}
+
+
+AlphabeticIndex & AlphabeticIndex::resetRecordIterator() {
+ itemsIterIndex_ = -1;
+ return *this;
+}
+
+
+
+AlphabeticIndex::Bucket::Bucket(const UnicodeString &label,
+ const UnicodeString &lowerBoundary,
+ UAlphabeticIndexLabelType type,
+ UErrorCode &status):
+ label_(label), lowerBoundary_(lowerBoundary), labelType_(type), records_(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ records_ = new UVector(status);
+ if (records_ == NULL && U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+
+AlphabeticIndex::Bucket::~Bucket() {
+ delete records_;
+}
+
+U_NAMESPACE_END
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/anytrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/anytrans.cpp
new file mode 100644
index 00000000000..7ce9ca71584
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/anytrans.cpp
@@ -0,0 +1,386 @@
+/*
+*****************************************************************
+* Copyright (c) 2002-2008, 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);
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ 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);
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ 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-4.8.1/i18n/anytrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/anytrans.h
new file mode 100644
index 00000000000..228ccbe03af
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/astro.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/astro.cpp
new file mode 100644
index 00000000000..95ddfa3d757
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/astro.cpp
@@ -0,0 +1,1590 @@
+/************************************************************************
+ * Copyright (C) 1996-2008, 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()
+
+#if defined (PI)
+#undef PI
+#endif
+
+#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
+
+/***
+ * Given 'value', add or subtract 'range' until 0 <= 'value' < range.
+ * The modulus operator.
+ */
+inline static double normalize(double value, double range) {
+ return value - range * ClockMath::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 + CalendarAstronomer::PI, CalendarAstronomer::PI * 2.0) - CalendarAstronomer::PI;
+}
+
+//-------------------------------------------------------------------------
+// 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 * ClockMath::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;
+// }
+
+/**
+ * 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
+ */
+static double 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) ) );
+}
+
+/**
+ * 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 = ClockMath::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);
+}
+ /**
+ * 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-4.8.1/i18n/astro.h b/Build/source/libs/icu/icu-4.8.1/i18n/astro.h
new file mode 100644
index 00000000000..cd20b6cf257
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/astro.h
@@ -0,0 +1,755 @@
+/************************************************************************
+ * Copyright (C) 1996-2008, 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:
+
+ /**
+ * 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-4.8.1/i18n/basictz.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/basictz.cpp
new file mode 100644
index 00000000000..6b4889a216c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/basictz.cpp
@@ -0,0 +1,560 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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
+ while (TRUE) {
+ if (avail1
+ && tr1.getTime() <= end
+ && (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);
+ } else {
+ break;
+ }
+ }
+ while (TRUE) {
+ if (avail2
+ && tr2.getTime() <= end
+ && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
+ == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
+ && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
+ tz.getNextTransition(tr2.getTime(), FALSE, tr2);
+ } else {
+ break;
+ }
+ }
+ }
+
+ 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);
+
+ // Note: SimpleTimeZone does not support raw offset change.
+ // So we always use raw offset of the given time for the rule,
+ // even raw offset is changed. This will result that the result
+ // zone to return wrong offset after the transition.
+ // When we encounter such case, we do not inspect next next
+ // transition for another rule.
+ ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
+ dtr, year, AnnualTimeZoneRule::MAX_YEAR);
+
+ if (tr.getTo()->getRawOffset() == initialRaw) {
+ // 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);
+
+ // second rule raw/dst offsets should match raw/dst offsets
+ // at the given time
+ ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
+ 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)) {
+ 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;
+ }
+ UDate updatedTime = tzt.getTime();
+ if (updatedTime == time) {
+ // Can get here if rules for start & end of daylight time have exactly
+ // the same time.
+ // TODO: fix getNextTransition() to prevent it?
+ status = U_INVALID_STATE_ERROR;
+ goto error;
+ }
+ time = updatedTime;
+
+ 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;
+ }
+ const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
+ const AnnualTimeZoneRule *ar;
+ if (tar != NULL) {
+ // 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 ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) {
+ 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) {
+ if (filteredRules != NULL) {
+ while (!filteredRules->isEmpty()) {
+ r = (TimeZoneRule*)filteredRules->orphanElementAt(0);
+ delete r;
+ }
+ delete filteredRules;
+ }
+ delete res_initial;
+ 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-4.8.1/i18n/bms.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/bms.cpp
new file mode 100644
index 00000000000..0a1de08b6fc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/bms.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2008-2011, International Business Machines Corporation and Others.
+ * All rights reserved.
+ */
+
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "unicode/bms.h"
+#include "unicode/unistr.h"
+#include "unicode/colldata.h"
+#include "unicode/bmsearch.h"
+
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+
+//#define USE_SAFE_CASTS
+#ifdef USE_SAFE_CASTS
+#define STATIC_CAST(type,value) static_cast<type>(value)
+#define CONST_CAST(type,value) const_cast<type>(value)
+#else
+#define STATIC_CAST(type,value) (type) (value)
+#define CONST_CAST(type,value) (type) (value)
+#endif
+
+U_NAMESPACE_USE
+
+U_CAPI UCD * U_EXPORT2
+ucd_open(UCollator *coll, UErrorCode *status)
+{
+ return STATIC_CAST(UCD *, CollData::open(coll, *status));
+}
+
+U_CAPI void U_EXPORT2
+ucd_close(UCD *ucd)
+{
+ if (ucd != NULL) {
+ CollData *data = STATIC_CAST(CollData *, ucd);
+
+ CollData::close(data);
+ }
+}
+
+U_CAPI UCollator * U_EXPORT2
+ucd_getCollator(UCD *ucd)
+{
+ CollData *data = STATIC_CAST(CollData *, ucd);
+
+ return data->getCollator();
+}
+
+U_CAPI void U_EXPORT2
+ucd_freeCache()
+{
+ CollData::freeCollDataCache();
+}
+
+U_CAPI void U_EXPORT2
+ucd_flushCache()
+{
+ CollData::flushCollDataCache();
+}
+
+struct BMS
+{
+ BoyerMooreSearch *bms;
+ const UnicodeString *targetString;
+};
+
+U_CAPI BMS * U_EXPORT2
+bms_open(UCD *ucd,
+ const UChar *pattern, int32_t patternLength,
+ const UChar *target, int32_t targetLength,
+ UErrorCode *status)
+{
+ BMS *bms = STATIC_CAST(BMS *, uprv_malloc(sizeof(BMS)));
+
+ if (bms == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ CollData *data = (CollData *) ucd;
+ UnicodeString patternString(pattern, patternLength);
+
+ if (target != NULL) {
+ bms->targetString = new UnicodeString(target, targetLength);
+
+ if (bms->targetString == NULL) {
+ bms->bms = NULL;
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return bms;
+ }
+ } else {
+ bms->targetString = NULL;
+ }
+
+ bms->bms = new BoyerMooreSearch(data, patternString, bms->targetString, *status);
+
+ if (bms->bms == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ return bms;
+}
+
+U_CAPI void U_EXPORT2
+bms_close(BMS *bms)
+{
+ delete bms->bms;
+
+ delete bms->targetString;
+
+ uprv_free(bms);
+}
+
+U_CAPI UBool U_EXPORT2
+bms_empty(BMS *bms)
+{
+ return bms->bms->empty();
+}
+
+U_CAPI UCD * U_EXPORT2
+bms_getData(BMS *bms)
+{
+ return STATIC_CAST(UCD *, bms->bms->getData());
+}
+
+U_CAPI UBool U_EXPORT2
+bms_search(BMS *bms, int32_t offset, int32_t *start, int32_t *end)
+{
+ return bms->bms->search(offset, *start, *end);
+}
+
+U_CAPI void U_EXPORT2
+bms_setTargetString(BMS *bms, const UChar *target, int32_t targetLength, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ if (bms->targetString != NULL) {
+ delete bms->targetString;
+ }
+
+ if (target != NULL) {
+ bms->targetString = new UnicodeString(target, targetLength);
+ } else {
+ bms->targetString = NULL;
+ }
+
+ bms->bms->setTargetString(bms->targetString, *status);
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/bmsearch.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/bmsearch.cpp
new file mode 100644
index 00000000000..4d2dcc5c9cc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/bmsearch.cpp
@@ -0,0 +1,827 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2011, International Business Machines *
+ * Corporation and others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/putil.h"
+#include "unicode/usearch.h"
+
+#include "cmemory.h"
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/ucoleitr.h"
+
+#include "unicode/regex.h" // TODO: make conditional on regexp being built.
+
+#include "unicode/uniset.h"
+#include "unicode/uset.h"
+#include "unicode/ustring.h"
+#include "hash.h"
+#include "uhash.h"
+#include "ucol_imp.h"
+#include "normalizer2impl.h"
+
+#include "unicode/colldata.h"
+#include "unicode/bmsearch.h"
+
+U_NAMESPACE_BEGIN
+
+#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))
+
+
+struct CEI
+{
+ uint32_t order;
+ int32_t lowOffset;
+ int32_t highOffset;
+};
+
+class Target : public UMemory
+{
+public:
+ Target(UCollator *theCollator, const UnicodeString *target, int32_t patternLength, UErrorCode &status);
+ ~Target();
+
+ void setTargetString(const UnicodeString *target);
+
+ const CEI *nextCE(int32_t offset);
+ const CEI *prevCE(int32_t offset);
+
+ int32_t stringLength();
+ UChar charAt(int32_t offset);
+
+ UBool isBreakBoundary(int32_t offset);
+ int32_t nextBreakBoundary(int32_t offset);
+ int32_t nextSafeBoundary(int32_t offset);
+
+ UBool isIdentical(UnicodeString &pattern, int32_t start, int32_t end);
+
+ void setOffset(int32_t offset);
+ void setLast(int32_t last);
+ int32_t getOffset();
+
+private:
+ CEI *ceb;
+ int32_t bufferSize;
+ int32_t bufferMin;
+ int32_t bufferMax;
+
+ uint32_t strengthMask;
+ UCollationStrength strength;
+ uint32_t variableTop;
+ UBool toShift;
+ UCollator *coll;
+ const Normalizer2 &nfd;
+
+ const UnicodeString *targetString;
+ const UChar *targetBuffer;
+ int32_t targetLength;
+
+ UCollationElements *elements;
+ UBreakIterator *charBreakIterator;
+};
+
+Target::Target(UCollator *theCollator, const UnicodeString *target, int32_t patternLength, UErrorCode &status)
+ : bufferSize(0), bufferMin(0), bufferMax(0),
+ strengthMask(0), strength(UCOL_PRIMARY), variableTop(0), toShift(FALSE), coll(theCollator),
+ nfd(*Normalizer2Factory::getNFDInstance(status)),
+ targetString(NULL), targetBuffer(NULL), targetLength(0), elements(NULL), charBreakIterator(NULL)
+{
+ strength = ucol_getStrength(coll);
+ toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, &status) == UCOL_SHIFTED;
+ variableTop = ucol_getVariableTop(coll, &status);
+
+ // find the largest expansion
+ uint8_t maxExpansion = 0;
+ for (const uint8_t *expansion = coll->expansionCESize; *expansion != 0; expansion += 1) {
+ if (*expansion > maxExpansion) {
+ maxExpansion = *expansion;
+ }
+ }
+
+ // room for an extra character on each end, plus 4 for safety
+ bufferSize = patternLength + (2 * maxExpansion) + 4;
+
+ ceb = NEW_ARRAY(CEI, bufferSize);
+
+ if (ceb == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ if (target != NULL) {
+ setTargetString(target);
+ }
+
+ switch (strength)
+ {
+ default:
+ strengthMask |= UCOL_TERTIARYORDERMASK;
+ /* fall through */
+
+ case UCOL_SECONDARY:
+ strengthMask |= UCOL_SECONDARYORDERMASK;
+ /* fall through */
+
+ case UCOL_PRIMARY:
+ strengthMask |= UCOL_PRIMARYORDERMASK;
+ }
+}
+
+Target::~Target()
+{
+ ubrk_close(charBreakIterator);
+ ucol_closeElements(elements);
+
+ DELETE_ARRAY(ceb);
+}
+
+void Target::setTargetString(const UnicodeString *target)
+{
+ if (charBreakIterator != NULL) {
+ ubrk_close(charBreakIterator);
+ ucol_closeElements(elements);
+ }
+
+ targetString = target;
+
+ if (targetString != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ targetBuffer = targetString->getBuffer();
+ targetLength = targetString->length();
+
+ elements = ucol_openElements(coll, target->getBuffer(), target->length(), &status);
+ ucol_forceHanImplicit(elements, &status);
+
+ charBreakIterator = ubrk_open(UBRK_CHARACTER, ucol_getLocaleByType(coll, ULOC_VALID_LOCALE, &status),
+ targetBuffer, targetLength, &status);
+ } else {
+ targetBuffer = NULL;
+ targetLength = 0;
+ }
+}
+
+const CEI *Target::nextCE(int32_t offset)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t low = -1, high = -1;
+ uint32_t order;
+ UBool cont = FALSE;
+
+ if (offset >= bufferMin && offset < bufferMax) {
+ return &ceb[offset];
+ }
+
+ if (bufferMax >= bufferSize || offset != bufferMax) {
+ return NULL;
+ }
+
+ do {
+ low = ucol_getOffset(elements);
+ order = ucol_next(elements, &status);
+ high = ucol_getOffset(elements);
+
+ if (order == (uint32_t)UCOL_NULLORDER) {
+ //high = low = -1;
+ break;
+ }
+
+ cont = isContinuation(order);
+ order &= strengthMask;
+
+ if (toShift && variableTop > order && (order & UCOL_PRIMARYORDERMASK) != 0) {
+ if (strength >= UCOL_QUATERNARY) {
+ order &= UCOL_PRIMARYORDERMASK;
+ } else {
+ order = UCOL_IGNORABLE;
+ }
+ }
+ } while (order == UCOL_IGNORABLE);
+
+ if (cont) {
+ order |= UCOL_CONTINUATION_MARKER;
+ }
+
+ ceb[offset].order = order;
+ ceb[offset].lowOffset = low;
+ ceb[offset].highOffset = high;
+
+ bufferMax += 1;
+
+ return &ceb[offset];
+}
+
+const CEI *Target::prevCE(int32_t offset)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t low = -1, high = -1;
+ uint32_t order;
+ UBool cont = FALSE;
+
+ if (offset >= bufferMin && offset < bufferMax) {
+ return &ceb[offset];
+ }
+
+ if (bufferMax >= bufferSize || offset != bufferMax) {
+ return NULL;
+ }
+
+ do {
+ high = ucol_getOffset(elements);
+ order = ucol_previous(elements, &status);
+ low = ucol_getOffset(elements);
+
+ if (order == (uint32_t)UCOL_NULLORDER) {
+ break;
+ }
+
+ cont = isContinuation(order);
+ order &= strengthMask;
+
+ if (toShift && variableTop > order && (order & UCOL_PRIMARYORDERMASK) != 0) {
+ if (strength >= UCOL_QUATERNARY) {
+ order &= UCOL_PRIMARYORDERMASK;
+ } else {
+ order = UCOL_IGNORABLE;
+ }
+ }
+ } while (order == UCOL_IGNORABLE);
+
+ bufferMax += 1;
+
+ if (cont) {
+ order |= UCOL_CONTINUATION_MARKER;
+ }
+
+ ceb[offset].order = order;
+ ceb[offset].lowOffset = low;
+ ceb[offset].highOffset = high;
+
+ return &ceb[offset];
+}
+
+int32_t Target::stringLength()
+{
+ if (targetString != NULL) {
+ return targetLength;
+ }
+
+ return 0;
+}
+
+UChar Target::charAt(int32_t offset)
+{
+ if (targetString != NULL) {
+ return targetBuffer[offset];
+ }
+
+ return 0x0000;
+}
+
+void Target::setOffset(int32_t offset)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ bufferMin = 0;
+ bufferMax = 0;
+
+ ucol_setOffset(elements, offset, &status);
+}
+
+void Target::setLast(int32_t last)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ bufferMin = 0;
+ bufferMax = 1;
+
+ ceb[0].order = UCOL_NULLORDER;
+ ceb[0].lowOffset = last;
+ ceb[0].highOffset = last;
+
+ ucol_setOffset(elements, last, &status);
+}
+
+int32_t Target::getOffset()
+{
+ return ucol_getOffset(elements);
+}
+
+UBool Target::isBreakBoundary(int32_t offset)
+{
+ return ubrk_isBoundary(charBreakIterator, offset);
+}
+
+int32_t Target::nextBreakBoundary(int32_t offset)
+{
+ return ubrk_following(charBreakIterator, offset);
+}
+
+int32_t Target::nextSafeBoundary(int32_t offset)
+{
+ while (offset < targetLength) {
+ //UChar ch = charAt(offset);
+ UChar ch = targetBuffer[offset];
+
+ if (U_IS_LEAD(ch) || ! ucol_unsafeCP(ch, coll)) {
+ return offset;
+ }
+
+ offset += 1;
+ }
+
+ return targetLength;
+}
+
+UBool Target::isIdentical(UnicodeString &pattern, int32_t start, int32_t end)
+{
+ if (strength < UCOL_IDENTICAL) {
+ return TRUE;
+ }
+
+ // Note: We could use Normalizer::compare() or similar, but for short strings
+ // which may not be in FCD it might be faster to just NFD them.
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString t2, p2;
+ nfd.normalize(UnicodeString(FALSE, targetBuffer + start, end - start), t2, status);
+ nfd.normalize(pattern, p2, status);
+ // return FALSE if NFD failed
+ return U_SUCCESS(status) && t2 == p2;
+}
+
+#define HASH_TABLE_SIZE 257
+
+class BadCharacterTable : public UMemory
+{
+public:
+ BadCharacterTable(CEList &patternCEs, CollData *data, UErrorCode &status);
+ ~BadCharacterTable();
+
+ int32_t operator[](uint32_t ce) const;
+ int32_t getMaxSkip() const;
+ int32_t minLengthInChars(int32_t index);
+
+private:
+ static int32_t hash(uint32_t ce);
+
+ int32_t maxSkip;
+ int32_t badCharacterTable[HASH_TABLE_SIZE];
+
+ int32_t *minLengthCache;
+};
+
+BadCharacterTable::BadCharacterTable(CEList &patternCEs, CollData *data, UErrorCode &status)
+ : minLengthCache(NULL)
+{
+ int32_t plen = patternCEs.size();
+
+ // **** need a better way to deal with this ****
+ if (U_FAILURE(status) || plen == 0) {
+ return;
+ }
+
+ int32_t *history = NEW_ARRAY(int32_t, plen);
+
+ if (history == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ for (int32_t i = 0; i < plen; i += 1) {
+ history[i] = -1;
+ }
+
+ minLengthCache = NEW_ARRAY(int32_t, plen + 1);
+
+ if (minLengthCache == NULL) {
+ DELETE_ARRAY(history);
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ maxSkip = minLengthCache[0] = data->minLengthInChars(&patternCEs, 0, history);
+
+ for(int32_t j = 0; j < HASH_TABLE_SIZE; j += 1) {
+ badCharacterTable[j] = maxSkip;
+ }
+
+ for(int32_t p = 1; p < plen; p += 1) {
+ minLengthCache[p] = data->minLengthInChars(&patternCEs, p, history);
+
+ // Make sure this entry is not bigger than the previous one.
+ // Otherwise, we might skip too far in some cases.
+ if (minLengthCache[p] < 0 || minLengthCache[p] > minLengthCache[p - 1]) {
+ minLengthCache[p] = minLengthCache[p - 1];
+ }
+ }
+
+ minLengthCache[plen] = 0;
+
+ for(int32_t p = 0; p < plen - 1; p += 1) {
+ badCharacterTable[hash(patternCEs[p])] = minLengthCache[p + 1];
+ }
+
+ DELETE_ARRAY(history);
+}
+
+BadCharacterTable::~BadCharacterTable()
+{
+ DELETE_ARRAY(minLengthCache);
+}
+
+int32_t BadCharacterTable::operator[](uint32_t ce) const
+{
+ return badCharacterTable[hash(ce)];
+}
+
+int32_t BadCharacterTable::getMaxSkip() const
+{
+ return maxSkip;
+}
+
+int32_t BadCharacterTable::minLengthInChars(int32_t index)
+{
+ return minLengthCache[index];
+}
+
+int32_t BadCharacterTable::hash(uint32_t ce)
+{
+ return UCOL_PRIMARYORDER(ce) % HASH_TABLE_SIZE;
+}
+
+class GoodSuffixTable : public UMemory
+{
+public:
+ GoodSuffixTable(CEList &patternCEs, BadCharacterTable &badCharacterTable, UErrorCode &status);
+ ~GoodSuffixTable();
+
+ int32_t operator[](int32_t offset) const;
+
+private:
+ int32_t *goodSuffixTable;
+};
+
+GoodSuffixTable::GoodSuffixTable(CEList &patternCEs, BadCharacterTable &badCharacterTable, UErrorCode &status)
+ : goodSuffixTable(NULL)
+{
+ int32_t patlen = patternCEs.size();
+
+ // **** need a better way to deal with this ****
+ if (U_FAILURE(status) || patlen <= 0) {
+ return;
+ }
+
+ int32_t *suff = NEW_ARRAY(int32_t, patlen);
+ int32_t start = patlen - 1, end = - 1;
+ int32_t maxSkip = badCharacterTable.getMaxSkip();
+
+ if (suff == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ // initialze suff
+ suff[patlen - 1] = patlen;
+
+ for (int32_t i = patlen - 2; i >= 0; i -= 1) {
+ // (i > start) means we're inside the last suffix match we found
+ // ((patlen - 1) - end) is how far the end of that match is from end of pattern
+ // (i - start) is how far we are from start of that match
+ // (i + (patlen - 1) - end) is index of same character at end of pattern
+ // so if any suffix match at that character doesn't extend beyond the last match,
+ // it's the suffix for this character as well
+ if (i > start && suff[i + patlen - 1 - end] < i - start) {
+ suff[i] = suff[i + patlen - 1 - end];
+ } else {
+ start = end = i;
+
+ int32_t s = patlen;
+
+ while (start >= 0 && patternCEs[start] == patternCEs[--s]) {
+ start -= 1;
+ }
+
+ suff[i] = end - start;
+ }
+ }
+
+ // now build goodSuffixTable
+ goodSuffixTable = NEW_ARRAY(int32_t, patlen);
+
+ if (goodSuffixTable == NULL) {
+ DELETE_ARRAY(suff);
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+
+ // initialize entries to minLengthInChars of the pattern
+ for (int32_t i = 0; i < patlen; i += 1) {
+ goodSuffixTable[i] = maxSkip;
+ }
+
+ int32_t prefix = 0;
+
+ for (int32_t i = patlen - /*1*/ 2; i >= 0; i -= 1) {
+ if (suff[i] == i + 1) {
+ // this matching suffix is a prefix of the pattern
+ int32_t prefixSkip = badCharacterTable.minLengthInChars(i + 1);
+
+ // for any mis-match before this suffix, we should skip
+ // so that the front of the pattern (i.e. the prefix)
+ // lines up with the front of the suffix.
+ // (patlen - 1 - i) is the start of the suffix
+ while (prefix < patlen - 1 - i) {
+ // value of maxSkip means never set...
+ if (goodSuffixTable[prefix] == maxSkip) {
+ goodSuffixTable[prefix] = prefixSkip;
+ }
+
+ prefix += 1;
+ }
+ }
+ }
+
+ for (int32_t i = 0; i < patlen - 1; i += 1) {
+ goodSuffixTable[patlen - 1 - suff[i]] = badCharacterTable.minLengthInChars(i + 1);
+ }
+
+ DELETE_ARRAY(suff);
+}
+
+GoodSuffixTable::~GoodSuffixTable()
+{
+ DELETE_ARRAY(goodSuffixTable);
+}
+
+int32_t GoodSuffixTable::operator[](int32_t offset) const
+{
+ return goodSuffixTable[offset];
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BoyerMooreSearch)
+
+
+UBool BoyerMooreSearch::empty()
+{
+ return patCEs->size() <= 0;
+}
+
+CollData *BoyerMooreSearch::getData()
+{
+ return data;
+}
+
+CEList *BoyerMooreSearch::getPatternCEs()
+{
+ return patCEs;
+}
+
+BadCharacterTable *BoyerMooreSearch::getBadCharacterTable()
+{
+ return badCharacterTable;
+}
+
+GoodSuffixTable *BoyerMooreSearch::getGoodSuffixTable()
+{
+ return goodSuffixTable;
+}
+
+BoyerMooreSearch::BoyerMooreSearch(CollData *theData, const UnicodeString &patternString, const UnicodeString *targetString,
+ UErrorCode &status)
+ : data(theData), patCEs(NULL), badCharacterTable(NULL), goodSuffixTable(NULL), pattern(patternString), target(NULL)
+{
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UCollator *collator = data->getCollator();
+
+ patCEs = new CEList(collator, patternString, status);
+
+ if (patCEs == NULL || U_FAILURE(status)) {
+ return;
+ }
+
+ badCharacterTable = new BadCharacterTable(*patCEs, data, status);
+
+ if (badCharacterTable == NULL || U_FAILURE(status)) {
+ return;
+ }
+
+ goodSuffixTable = new GoodSuffixTable(*patCEs, *badCharacterTable, status);
+
+ if (targetString != NULL) {
+ target = new Target(collator, targetString, patCEs->size(), status);
+ }
+}
+
+BoyerMooreSearch::~BoyerMooreSearch()
+{
+ delete target;
+ delete goodSuffixTable;
+ delete badCharacterTable;
+ delete patCEs;
+}
+
+void BoyerMooreSearch::setTargetString(const UnicodeString *targetString, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (target == NULL) {
+ target = new Target(data->getCollator(), targetString, patCEs->size(), status);
+ } else {
+ target->setTargetString(targetString);
+ }
+}
+
+// **** main flow of this code from Laura Werner's "Unicode Text Searching in Java" paper. ****
+/*
+ * TODO:
+ * * deal with trailing (and leading?) ignorables.
+ * * Adding BoyerMooreSearch object slowed it down. How can we speed it up?
+ */
+UBool BoyerMooreSearch::search(int32_t offset, int32_t &start, int32_t &end)
+{
+ /*UCollator *coll =*/ data->getCollator();
+ int32_t plen = patCEs->size();
+ int32_t tlen = target->stringLength();
+ int32_t maxSkip = badCharacterTable->getMaxSkip();
+ int32_t tOffset = offset + maxSkip;
+
+ if (plen <= 0) {
+ // Searching for a zero length pattern always fails.
+ start = end = -1;
+ return FALSE;
+ }
+
+ while (tOffset <= tlen) {
+ int32_t pIndex = plen - 1;
+ int32_t tIndex = 0;
+ int32_t lIndex = 0;
+
+ if (tOffset < tlen) {
+ // **** we really want to skip ahead enough to ****
+ // **** be sure we get at least 1 non-ignorable ****
+ // **** CE after the end of the pattern. ****
+ int32_t next = target->nextSafeBoundary(tOffset + 1);
+
+ target->setOffset(next);
+
+ for (lIndex = 0; ; lIndex += 1) {
+ const CEI *cei = target->prevCE(lIndex);
+ int32_t low = cei->lowOffset;
+ int32_t high = cei->highOffset;
+
+ if (high == 0 || (low < high && low <= tOffset)) {
+ if (low < tOffset) {
+ while (lIndex >= 0 && target->prevCE(lIndex)->highOffset == high) {
+ lIndex -= 1;
+ }
+
+ if (high > tOffset) {
+ tOffset = high;
+ }
+ }
+
+ break;
+ }
+ }
+ } else {
+ target->setLast(tOffset);
+ lIndex = 0;
+ }
+
+ tIndex = ++lIndex;
+
+ // Iterate backward until we hit the beginning of the pattern
+ while (pIndex >= 0) {
+ uint32_t pce = (*patCEs)[pIndex];
+ const CEI *tcei = target->prevCE(tIndex++);
+
+
+ if (tcei->order != pce) {
+ // There is a mismatch at this position. Decide how far
+ // over to shift the pattern, then try again.
+
+ int32_t gsOffset = tOffset + (*goodSuffixTable)[pIndex];
+#ifdef EXTRA_CAUTIOUS
+ int32_t old = tOffset;
+#endif
+
+ tOffset += (*badCharacterTable)[tcei->order] - badCharacterTable->minLengthInChars(pIndex + 1);
+
+ if (gsOffset > tOffset) {
+ tOffset = gsOffset;
+ }
+
+#ifdef EXTRA_CAUTIOUS
+ // Make sure we don't skip backwards...
+ if (tOffset <= old) {
+ tOffset = old + 1;
+ }
+#endif
+
+ break;
+ }
+
+ pIndex -= 1;
+ }
+
+ if (pIndex < 0) {
+ // We made it back to the beginning of the pattern,
+ // which means we matched it all. Return the location.
+ const CEI firstCEI = *target->prevCE(tIndex - 1);
+ const CEI lastCEI = *target->prevCE(lIndex);
+ int32_t mStart = firstCEI.lowOffset;
+ int32_t minLimit = lastCEI.lowOffset;
+ int32_t maxLimit = lastCEI.highOffset;
+ int32_t mLimit;
+ UBool found = TRUE;
+
+ target->setOffset(/*tOffset*/maxLimit);
+
+ const CEI nextCEI = *target->nextCE(0);
+
+ if (nextCEI.lowOffset > maxLimit) {
+ maxLimit = nextCEI.lowOffset;
+ }
+
+ if (nextCEI.lowOffset == nextCEI.highOffset && nextCEI.order != (uint32_t)UCOL_NULLORDER) {
+ found = FALSE;
+ }
+
+ if (! target->isBreakBoundary(mStart)) {
+ found = FALSE;
+ }
+
+ if (firstCEI.lowOffset == firstCEI.highOffset) {
+ found = FALSE;
+ }
+
+ mLimit = maxLimit;
+ if (minLimit < maxLimit) {
+ // When the last CE's low index is same with its high index, the CE is likely
+ // a part of expansion. In this case, the index is located just after the
+ // character corresponding to the CEs compared above. If the index is right
+ // at the break boundary, move the position to the next boundary will result
+ // incorrect match length when there are ignorable characters exist between
+ // the position and the next character produces CE(s). See ticket#8482.
+ if (minLimit == lastCEI.highOffset && target->isBreakBoundary(minLimit)) {
+ mLimit = minLimit;
+ } else {
+ int32_t nbb = target->nextBreakBoundary(minLimit);
+
+ if (nbb >= lastCEI.highOffset) {
+ mLimit = nbb;
+ }
+ }
+ }
+
+ if (mLimit > maxLimit) {
+ found = FALSE;
+ }
+
+ if (! target->isBreakBoundary(mLimit)) {
+ found = FALSE;
+ }
+
+ if (! target->isIdentical(pattern, mStart, mLimit)) {
+ found = FALSE;
+ }
+
+ if (found) {
+ start = mStart;
+ end = mLimit;
+
+ return TRUE;
+ }
+
+ tOffset += (*goodSuffixTable)[0]; // really? Maybe += 1 or += maxSkip?
+ }
+ // Otherwise, we're here because of a mismatch, so keep going....
+ }
+
+ // no match
+ start = -1;
+ end = -1;
+ return FALSE;
+}
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_COLLATION
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/bocsu.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/bocsu.cpp
new file mode 100644
index 00000000000..6e473dcfc87
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/bocsu.cpp
@@ -0,0 +1,153 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: bocsu.cpp
+* 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"
+#include "unicode/bytestream.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;
+}
+
+/*
+ * 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 void
+u_writeIdenticalLevelRun(const UChar *s, int32_t length, U_NAMESPACE_QUALIFIER ByteSink &sink) {
+ char scratch[64];
+ int32_t capacity;
+
+ UChar32 prev=0;
+ int32_t i=0;
+ while(i<length) {
+ char *buffer=sink.GetAppendBuffer(1, length*2, scratch, (int32_t)sizeof(scratch), &capacity);
+ uint8_t *p;
+ // We must have capacity>=SLOPE_MAX_BYTES in case u_writeDiff() writes that much,
+ // but we do not want to force the sink.GetAppendBuffer() to allocate
+ // for a large min_capacity because we might actually only write one byte.
+ if(capacity<16) {
+ buffer=scratch;
+ capacity=(int32_t)sizeof(scratch);
+ }
+ p=reinterpret_cast<uint8_t *>(buffer);
+ uint8_t *lastSafe=p+capacity-SLOPE_MAX_BYTES;
+ while(i<length && p<=lastSafe) {
+ 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;
+ }
+
+ UChar32 c;
+ U16_NEXT(s, i, length, c);
+ p=u_writeDiff(c-prev, p);
+ prev=c;
+ }
+ sink.Append(buffer, (int32_t)(p-reinterpret_cast<uint8_t *>(buffer)));
+ }
+}
+
+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);
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/bocsu.h b/Build/source/libs/icu/icu-4.8.1/i18n/bocsu.h
new file mode 100644
index 00000000000..ebad816b18e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/bocsu.h
@@ -0,0 +1,165 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2011, 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
+
+U_NAMESPACE_BEGIN
+
+class ByteSink;
+
+U_NAMESPACE_END
+
+/*
+ * "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 void
+u_writeIdenticalLevelRun(const UChar *s, int32_t length, U_NAMESPACE_QUALIFIER ByteSink &sink);
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRunTwoChars(UChar32 first, UChar32 second, uint8_t *p);
+
+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-4.8.1/i18n/brktrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/brktrans.cpp
new file mode 100644
index 00000000000..52072667839
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/brktrans.cpp
@@ -0,0 +1,188 @@
+/*
+**********************************************************************
+* Copyright (C) 2008-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/11/2008 Andy Heninger Port from Java
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/unifilt.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/brkiter.h"
+#include "brktrans.h"
+#include "unicode/uchar.h"
+#include "cmemory.h"
+#include "uprops.h"
+#include "uinvchar.h"
+#include "util.h"
+#include "uvectr32.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BreakTransliterator)
+
+static const UChar SPACE = 32; // ' '
+
+
+/**
+ * Constructs a transliterator with the default delimiters '{' and
+ * '}'.
+ */
+BreakTransliterator::BreakTransliterator(UnicodeFilter* adoptedFilter) :
+ Transliterator(UNICODE_STRING("Any-BreakInternal", 17), adoptedFilter),
+ fInsertion(SPACE) {
+ bi = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ boundaries = new UVector32(status);
+ }
+
+
+/**
+ * Destructor.
+ */
+BreakTransliterator::~BreakTransliterator() {
+ delete bi;
+ bi = NULL;
+ delete boundaries;
+ boundaries = NULL;
+}
+
+/**
+ * Copy constructor.
+ */
+BreakTransliterator::BreakTransliterator(const BreakTransliterator& o) :
+ Transliterator(o) {
+ bi = NULL;
+ if (o.bi != NULL) {
+ bi = o.bi->clone();
+ }
+ fInsertion = o.fInsertion;
+ UErrorCode status = U_ZERO_ERROR;
+ boundaries = new UVector32(status);
+ }
+
+
+/**
+ * Transliterator API.
+ */
+Transliterator* BreakTransliterator::clone(void) const {
+ return new BreakTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void BreakTransliterator::handleTransliterate(Replaceable& text, UTransPosition& offsets,
+ UBool isIncremental ) const {
+
+ UErrorCode status = U_ZERO_ERROR;
+ boundaries->removeAllElements();
+ BreakTransliterator *nonConstThis = (BreakTransliterator *)this;
+ nonConstThis->getBreakIterator(); // Lazy-create it if necessary
+ UnicodeString sText = replaceableAsString(text);
+ bi->setText(sText);
+ bi->preceding(offsets.start);
+
+ // To make things much easier, we will stack the boundaries, and then insert at the end.
+ // generally, we won't need too many, since we will be filtered.
+
+ int32_t boundary;
+ for(boundary = bi->next(); boundary != UBRK_DONE && boundary < offsets.limit; boundary = bi->next()) {
+ if (boundary == 0) continue;
+ // HACK: Check to see that preceeding item was a letter
+
+ UChar32 cp = sText.char32At(boundary-1);
+ int type = u_charType(cp);
+ //System.out.println(Integer.toString(cp,16) + " (before): " + type);
+ if ((U_MASK(type) & (U_GC_L_MASK | U_GC_M_MASK)) == 0) continue;
+
+ cp = sText.char32At(boundary);
+ type = u_charType(cp);
+ //System.out.println(Integer.toString(cp,16) + " (after): " + type);
+ if ((U_MASK(type) & (U_GC_L_MASK | U_GC_M_MASK)) == 0) continue;
+
+ boundaries->addElement(boundary, status);
+ // printf("Boundary at %d\n", boundary);
+ }
+
+ int delta = 0;
+ int lastBoundary = 0;
+
+ if (boundaries->size() != 0) { // if we found something, adjust
+ delta = boundaries->size() * fInsertion.length();
+ lastBoundary = boundaries->lastElementi();
+
+ // we do this from the end backwards, so that we don't have to keep updating.
+
+ while (boundaries->size() > 0) {
+ boundary = boundaries->popi();
+ text.handleReplaceBetween(boundary, boundary, fInsertion);
+ }
+ }
+
+ // Now fix up the return values
+ offsets.contextLimit += delta;
+ offsets.limit += delta;
+ offsets.start = isIncremental ? lastBoundary + delta : offsets.limit;
+
+ // TODO: do something with U_FAILURE(status);
+ // (need to look at transliterators overall, not just here.)
+}
+
+//
+// getInsertion()
+//
+const UnicodeString &BreakTransliterator::getInsertion() const {
+ return fInsertion;
+}
+
+//
+// setInsertion()
+//
+void BreakTransliterator::setInsertion(const UnicodeString &insertion) {
+ this->fInsertion = insertion;
+}
+
+//
+// getBreakIterator Lazily create the break iterator if it does
+// not already exist. Copied from Java, probably
+// better to just create it in the constructor.
+//
+BreakIterator *BreakTransliterator::getBreakIterator() {
+ UErrorCode status = U_ZERO_ERROR;
+ if (bi == NULL) {
+ // Note: Thai breaking behavior is universal, it is not
+ // tied to the Thai locale.
+ bi = BreakIterator::createWordInstance(Locale::getEnglish(), status);
+ }
+ return bi;
+}
+
+//
+// replaceableAsString Hack to let break iterators work
+// on the replaceable text from transliterators.
+// In practice, the only real Replaceable type that we
+// will be seeing is UnicodeString, so this function
+// will normally be efficient.
+//
+UnicodeString BreakTransliterator::replaceableAsString(Replaceable &r) {
+ UnicodeString s;
+ UnicodeString *rs = dynamic_cast<UnicodeString *>(&r);
+ if (rs != NULL) {
+ s = *rs;
+ } else {
+ r.extractBetween(0, r.length(), s);
+ }
+ return s;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/brktrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/brktrans.h
new file mode 100644
index 00000000000..00701181d36
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/brktrans.h
@@ -0,0 +1,113 @@
+/*
+**********************************************************************
+* Copyright (C) 2008-2009, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/11/2008 Andy Heninger Ported from Java
+**********************************************************************
+*/
+#ifndef BRKTRANS_H
+#define BRKTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/translit.h"
+
+
+U_NAMESPACE_BEGIN
+
+class UVector32;
+
+/**
+ * A transliterator that pInserts the specified characters at word breaks.
+ * To restrict it to particular characters, use a filter.
+ * TODO: this is an internal class, and only temporary.
+ * Remove it once we have \b notation in Transliterator.
+ */
+class BreakTransliterator : public Transliterator {
+public:
+
+ BreakTransliterator(const UnicodeString &ID,
+ UnicodeFilter *adoptedFilter,
+ BreakIterator *bi,
+ const UnicodeString &insertion);
+ /**
+ * Constructs a transliterator.
+ * @param adoptedFilter the filter for this transliterator.
+ */
+ BreakTransliterator(UnicodeFilter* adoptedFilter = 0);
+
+ /**
+ * Destructor.
+ */
+ virtual ~BreakTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ BreakTransliterator(const BreakTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return A copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ virtual const UnicodeString &getInsertion() const;
+
+ virtual void setInsertion(const UnicodeString &insertion);
+
+ /**
+ * Return the break iterator used by this transliterator.
+ * Caution, this is the live break iterator; it must not be used while
+ * there is any possibility that this transliterator is using it.
+ */
+ virtual BreakIterator *getBreakIterator();
+
+
+ /**
+ * 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:
+ BreakIterator *bi;
+ UnicodeString fInsertion;
+ UVector32 *boundaries;
+ UnicodeString sText; // text from handleTransliterate().
+
+ static UnicodeString replaceableAsString(Replaceable &r);
+
+ /**
+ * Assignment operator.
+ */
+ BreakTransliterator& operator=(const BreakTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/buddhcal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/buddhcal.cpp
new file mode 100644
index 00000000000..92f726c3028
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/buddhcal.cpp
@@ -0,0 +1,212 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003-2008, 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.
+ 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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ 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-4.8.1/i18n/buddhcal.h b/Build/source/libs/icu/icu-4.8.1/i18n/buddhcal.h
new file mode 100644
index 00000000000..735f61890a7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/calendar.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/calendar.cpp
new file mode 100644
index 00000000000..6b398937de0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/calendar.cpp
@@ -0,0 +1,3418 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 <typeinfo> // for 'typeid' to work
+
+#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 "coptccal.h"
+#include "ethpccal.h"
+#include "unicode/calendar.h"
+#include "cpputils.h"
+#include "servloc.h"
+#include "ucln_in.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "uresimp.h"
+#include "ustrenum.h"
+
+#if !UCONFIG_NO_SERVICE
+static icu::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)
+
+/**
+ * fldName was removed as a duplicate implementation.
+ * use udbg_ services instead,
+ * which depend on include files and library from ../tools/ctestfw
+ */
+#include "unicode/udbgutil.h"
+#include <stdio.h>
+
+/**
+* convert a UCalendarDateFields into a string - for debugging
+* @param f field enum
+* @return static string to the field name
+* @internal
+*/
+
+const char* fldName(UCalendarDateFields f) {
+ return udbg_enumName(UDBG_UCalendarDateFields, (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
+
+/* Max value for stamp allowable before recalculation */
+#define STAMP_MAX 10000
+
+static const char * const gCalTypes[] = {
+ "gregorian",
+ "japanese",
+ "buddhist",
+ "roc",
+ "persian",
+ "islamic-civil",
+ "islamic",
+ "hebrew",
+ "chinese",
+ "indian",
+ "coptic",
+ "ethiopic",
+ "ethiopic-amete-alem",
+ "iso8601",
+ NULL
+};
+
+// Must be in the order of gCalTypes above
+typedef enum ECalType {
+ CALTYPE_UNKNOWN = -1,
+ CALTYPE_GREGORIAN = 0,
+ CALTYPE_JAPANESE,
+ CALTYPE_BUDDHIST,
+ CALTYPE_ROC,
+ CALTYPE_PERSIAN,
+ CALTYPE_ISLAMIC_CIVIL,
+ CALTYPE_ISLAMIC,
+ CALTYPE_HEBREW,
+ CALTYPE_CHINESE,
+ CALTYPE_INDIAN,
+ CALTYPE_COPTIC,
+ CALTYPE_ETHIOPIC,
+ CALTYPE_ETHIOPIC_AMETE_ALEM,
+ CALTYPE_ISO8601
+} ECalType;
+
+U_NAMESPACE_BEGIN
+
+static ECalType getCalendarType(const char *s) {
+ for (int i = 0; gCalTypes[i] != NULL; i++) {
+ if (uprv_stricmp(s, gCalTypes[i]) == 0) {
+ return (ECalType)i;
+ }
+ }
+ return CALTYPE_UNKNOWN;
+}
+
+static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return FALSE;
+ }
+ ECalType calType = getCalendarType(keyword);
+ return (calType != CALTYPE_UNKNOWN);
+}
+
+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 ECalType getCalendarTypeForLocale(const char *locid) {
+ UErrorCode status = U_ZERO_ERROR;
+ ECalType calType = CALTYPE_UNKNOWN;
+
+ //TODO: ULOC_FULL_NAME is out of date and too small..
+ char canonicalName[256];
+
+ // canonicalize, so grandfathered variant will be transformed to keywords
+ // e.g ja_JP_TRADITIONAL -> ja_JP@calendar=japanese
+ int32_t canonicalLen = uloc_canonicalize(locid, canonicalName, sizeof(canonicalName) - 1, &status);
+ if (U_FAILURE(status)) {
+ return CALTYPE_GREGORIAN;
+ }
+ canonicalName[canonicalLen] = 0; // terminate
+
+ char calTypeBuf[32];
+ int32_t calTypeBufLen;
+
+ calTypeBufLen = uloc_getKeywordValue(canonicalName, "calendar", calTypeBuf, sizeof(calTypeBuf) - 1, &status);
+ if (U_SUCCESS(status)) {
+ calTypeBuf[calTypeBufLen] = 0;
+ calType = getCalendarType(calTypeBuf);
+ if (calType != CALTYPE_UNKNOWN) {
+ return calType;
+ }
+ }
+ status = U_ZERO_ERROR;
+
+ // when calendar keyword is not available or not supported, read supplementalData
+ // to get the default calendar type for the locale's region
+ char region[ULOC_COUNTRY_CAPACITY];
+ int32_t regionLen = 0;
+ regionLen = uloc_getCountry(canonicalName, region, sizeof(region) - 1, &status);
+ if (regionLen == 0) {
+ char fullLoc[256];
+ int32_t fullLocLen = 0;
+ fullLocLen = uloc_addLikelySubtags(locid, fullLoc, sizeof(fullLoc) - 1, &status);
+ regionLen = uloc_getCountry(fullLoc, region, sizeof(region) - 1, &status);
+ }
+ if (U_FAILURE(status)) {
+ return CALTYPE_GREGORIAN;
+ }
+ region[regionLen] = 0;
+
+ // Read preferred calendar values from supplementalData calendarPreference
+ UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);
+ ures_getByKey(rb, "calendarPreferenceData", rb, &status);
+ UResourceBundle *order = ures_getByKey(rb, region, NULL, &status);
+ if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
+ status = U_ZERO_ERROR;
+ order = ures_getByKey(rb, "001", NULL, &status);
+ }
+
+ calTypeBuf[0] = 0;
+ if (U_SUCCESS(status) && order != NULL) {
+ // the first calender type is the default for the region
+ int32_t len = 0;
+ const UChar *uCalType = ures_getStringByIndex(order, 0, &len, &status);
+ if (len < (int32_t)sizeof(calTypeBuf)) {
+ u_UCharsToChars(uCalType, calTypeBuf, len);
+ *(calTypeBuf + len) = 0; // terminate;
+ calType = getCalendarType(calTypeBuf);
+ }
+ }
+
+ ures_close(order);
+ ures_close(rb);
+
+ if (calType == CALTYPE_UNKNOWN) {
+ // final fallback
+ calType = CALTYPE_GREGORIAN;
+ }
+ return calType;
+}
+
+static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UErrorCode& status) {
+ Calendar *cal = NULL;
+
+ switch (calType) {
+ case CALTYPE_GREGORIAN:
+ cal = new GregorianCalendar(loc, status);
+ break;
+ case CALTYPE_JAPANESE:
+ cal = new JapaneseCalendar(loc, status);
+ break;
+ case CALTYPE_BUDDHIST:
+ cal = new BuddhistCalendar(loc, status);
+ break;
+ case CALTYPE_ROC:
+ cal = new TaiwanCalendar(loc, status);
+ break;
+ case CALTYPE_PERSIAN:
+ cal = new PersianCalendar(loc, status);
+ break;
+ case CALTYPE_ISLAMIC_CIVIL:
+ cal = new IslamicCalendar(loc, status, IslamicCalendar::CIVIL);
+ break;
+ case CALTYPE_ISLAMIC:
+ cal = new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL);
+ break;
+ case CALTYPE_HEBREW:
+ cal = new HebrewCalendar(loc, status);
+ break;
+ case CALTYPE_CHINESE:
+ cal = new ChineseCalendar(loc, status);
+ break;
+ case CALTYPE_INDIAN:
+ cal = new IndianCalendar(loc, status);
+ break;
+ case CALTYPE_COPTIC:
+ cal = new CopticCalendar(loc, status);
+ break;
+ case CALTYPE_ETHIOPIC:
+ cal = new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA);
+ break;
+ case CALTYPE_ETHIOPIC_AMETE_ALEM:
+ cal = new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA);
+ break;
+ case CALTYPE_ISO8601:
+ cal = new GregorianCalendar(loc, status);
+ cal->setFirstDayOfWeek(UCAL_MONDAY);
+ cal->setMinimalDaysInFirstWeek(4);
+ break;
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return cal;
+}
+
+
+#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;gCalTypes[i] != NULL;i++) {
+ UnicodeString id((UChar)0x40); /* '@' a variant character */
+ id.append(UNICODE_STRING_SIMPLE("calendar="));
+ id.append(UnicodeString(gCalTypes[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(dynamic_cast<const LocaleKey*>(&key) == NULL) {
+ 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(getCalendarType(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 *ret = new UnicodeString();
+ if (ret == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ ret->append((UChar)0x40); // '@' is a variant character
+ ret->append(UNICODE_STRING("calendar=", 9));
+ ret->append(UnicodeString(gCalTypes[getCalendarTypeForLocale(loc.getName())], -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 {
+ UnicodeString *s = dynamic_cast<UnicodeString *>(instance);
+ if(s != NULL) {
+ return s->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();
+ if (newservice == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return newservice;
+ }
+#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
+ { 0, 0, 1, 1 }, // IS_LEAP_MONTH
+};
+
+// Resource bundle tags read by this class
+static const char gMonthNames[] = "monthNames";
+
+// 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();
+ if (fZone == NULL) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ }
+ setWeekData(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;
+
+ setWeekData(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();
+ if (fZone == NULL) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ }
+ setWeekData(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;
+ if (fZone != NULL) {
+ delete fZone;
+ }
+ if (right.fZone != NULL) {
+ fZone = right.fZone->clone();
+ }
+ fFirstDayOfWeek = right.fFirstDayOfWeek;
+ fMinimalDaysInFirstWeek = right.fMinimalDaysInFirstWeek;
+ fWeekendOnset = right.fWeekendOnset;
+ fWeekendOnsetMillis = right.fWeekendOnsetMillis;
+ fWeekendCease = right.fWeekendCease;
+ fWeekendCeaseMillis = right.fWeekendCeaseMillis;
+ 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)
+{
+ if (U_FAILURE(success)) {
+ return NULL;
+ }
+
+ Locale actualLoc;
+ UObject* u = NULL;
+
+#if !UCONFIG_NO_SERVICE
+ if (isCalendarServiceUsed()) {
+ u = getCalendarService(success)->get(aLocale, LocaleKey::KIND_ANY, &actualLoc, success);
+ }
+ else
+#endif
+ {
+ u = createStandardCalendar(getCalendarTypeForLocale(aLocale.getName()), 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
+ const UnicodeString* str = dynamic_cast<const UnicodeString*>(u);
+ if(str != NULL) {
+ // It's a unicode string telling us what type of calendar to load ("gregorian", etc)
+ // 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;
+ }
+
+ str = dynamic_cast<const UnicodeString*>(c);
+ if(str != NULL) {
+ // recursed! Second lookup returned a UnicodeString.
+ // Perhaps DefaultCalendar{} was set to another locale.
+#ifdef U_DEBUG_CALSVC
+ char tmp[200];
+ // 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->setWeekData(aLocale, c->getType(), success); // set the correct locale (this was an indirected calendar)
+
+ char keyword[ULOC_FULLNAME_CAPACITY];
+ UErrorCode tmpStatus = U_ZERO_ERROR;
+ l.getKeywordValue("calendar", keyword, ULOC_FULLNAME_CAPACITY, tmpStatus);
+ if (U_SUCCESS(tmpStatus) && uprv_strcmp(keyword, "iso8601") == 0) {
+ c->setFirstDayOfWeek(UCAL_MONDAY);
+ c->setMinimalDaysInFirstWeek(4);
+ }
+ }
+ 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 typeid(*this) == typeid(other) &&
+ fLenient == other.fLenient &&
+ fFirstDayOfWeek == other.fFirstDayOfWeek &&
+ fMinimalDaysInFirstWeek == other.fMinimalDaysInFirstWeek &&
+ fWeekendOnset == other.fWeekendOnset &&
+ fWeekendOnsetMillis == other.fWeekendOnsetMillis &&
+ fWeekendCease == other.fWeekendCease &&
+ fWeekendCeaseMillis == other.fWeekendCeaseMillis &&
+ *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);
+}
+
+// -------------------------------------
+
+StringEnumeration* U_EXPORT2
+Calendar::getKeywordValuesForLocale(const char* key,
+ const Locale& locale, UBool commonlyUsed, UErrorCode& status)
+{
+ // This is a wrapper over ucal_getKeywordValuesForLocale
+ UEnumeration *uenum = ucal_getKeywordValuesForLocale(key, locale.getName(),
+ commonlyUsed, &status);
+ if (U_FAILURE(status)) {
+ uenum_close(uenum);
+ return NULL;
+ }
+ return new UStringEnumeration(uenum);
+}
+
+// -------------------------------------
+
+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;
+
+ for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
+ fFields[i] = 0;
+ fStamp[i] = kUnset;
+ fIsSet[i] = FALSE;
+ }
+
+
+}
+
+// -------------------------------------
+
+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;
+ /* Ensure that the fNextStamp value doesn't go pass max value for int32_t */
+ if (fNextStamp == STAMP_MAX) {
+ recalculateStamp();
+ }
+ 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)ClockMath::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.
+*/
+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 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 = eyear;
+ 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 {
+ min = max;
+ 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 {
+ min = max;
+ 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;
+}
+
+// -------------------------------------
+// weekend functions, just dummy implementations for now (for API freeze)
+
+UCalendarWeekdayType
+Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const
+{
+ if (U_FAILURE(status)) {
+ return UCAL_WEEKDAY;
+ }
+ if (dayOfWeek < UCAL_SUNDAY || dayOfWeek > UCAL_SATURDAY) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return UCAL_WEEKDAY;
+ }
+ if (fWeekendOnset < fWeekendCease) {
+ if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) {
+ return UCAL_WEEKDAY;
+ }
+ } else {
+ if (dayOfWeek > fWeekendCease && dayOfWeek < fWeekendOnset) {
+ return UCAL_WEEKDAY;
+ }
+ }
+ if (dayOfWeek == fWeekendOnset) {
+ return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
+ }
+ if (dayOfWeek == fWeekendCease) {
+ return (fWeekendCeaseMillis == 0) ? UCAL_WEEKDAY : UCAL_WEEKEND_CEASE;
+ }
+ return UCAL_WEEKEND;
+}
+
+int32_t
+Calendar::getWeekendTransition(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ if (dayOfWeek == fWeekendOnset) {
+ return fWeekendOnsetMillis;
+ } else if (dayOfWeek == fWeekendCease) {
+ return fWeekendCeaseMillis;
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+}
+
+UBool
+Calendar::isWeekend(UDate date, UErrorCode &status) const
+{
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ // clone the calendar so we don't mess with the real one.
+ Calendar *work = (Calendar*)this->clone();
+ if (work == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ UBool result = FALSE;
+ work->setTime(date, status);
+ if (U_SUCCESS(status)) {
+ result = work->isWeekend();
+ }
+ delete work;
+ return result;
+}
+
+UBool
+Calendar::isWeekend(void) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UCalendarDaysOfWeek dayOfWeek = (UCalendarDaysOfWeek)get(UCAL_DAY_OF_WEEK, status);
+ UCalendarWeekdayType dayType = getDayOfWeekType(dayOfWeek, status);
+ if (U_SUCCESS(status)) {
+ switch (dayType) {
+ case UCAL_WEEKDAY:
+ return FALSE;
+ case UCAL_WEEKEND:
+ return TRUE;
+ case UCAL_WEEKEND_ONSET:
+ case UCAL_WEEKEND_CEASE:
+ // Use internalGet() because the above call to get() populated all fields.
+ {
+ int32_t millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);
+ int32_t transitionMillis = getWeekendTransition(dayOfWeek, status);
+ if (U_SUCCESS(status)) {
+ return (dayType == UCAL_WEEKEND_ONSET)?
+ (millisInDay >= transitionMillis):
+ (millisInDay < transitionMillis);
+ }
+ // else fall through, return FALSE
+ }
+ default:
+ break;
+ }
+ }
+ return FALSE;
+}
+
+// ------------------------------------- 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:
+ case UCAL_IS_LEAP_MONTH:
+ return kCalendarLimits[field][limitType];
+
+ case UCAL_WEEK_OF_MONTH:
+ {
+ int32_t limit;
+ if (limitType == UCAL_LIMIT_MINIMUM) {
+ limit = getMinimalDaysInFirstWeek() == 1 ? 1 : 0;
+ } else if (limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
+ limit = 1;
+ } else {
+ int32_t minDaysInFirst = getMinimalDaysInFirstWeek();
+ int32_t daysInMonth = handleGetLimit(UCAL_DAY_OF_MONTH, limitType);
+ if (limitType == UCAL_LIMIT_LEAST_MAXIMUM) {
+ limit = (daysInMonth + (7 - minDaysInFirst)) / 7;
+ } else { // limitType == UCAL_LIMIT_MAXIMUM
+ limit = (daysInMonth + 6 + (7 - minDaysInFirst)) / 7;
+ }
+ }
+ return limit;
+ }
+ 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();
+ if (work == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ 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 (fStamp[field] >= kMinimumUserStamp) {
+ 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)ClockMath::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(year);
+ }
+
+ 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(year, 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(int32_t /*eyear*/)
+{
+ return 0;
+}
+
+int32_t
+Calendar::getDefaultDayInMonth(int32_t /*eyear*/, 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->setLenient(TRUE);
+ 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->setLenient(TRUE);
+ 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_EXTENDED_YEAR:
+ set(UCAL_DAY_OF_YEAR, getGreatestMinimum(UCAL_DAY_OF_YEAR));
+ break;
+
+ case UCAL_YEAR_WOY:
+ set(UCAL_WEEK_OF_YEAR, getGreatestMinimum(UCAL_WEEK_OF_YEAR));
+
+ 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:
+ break;
+ }
+
+ // 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; }
+
+ // need to resolve time here, otherwise, fields set for actual limit
+ // may cause conflict with fields previously set (but not yet resolved).
+ work->complete(status);
+
+ work->setLenient(TRUE);
+ work->prepareGetActual(field, delta < 0, status);
+
+ // 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
+ work->set(field, startValue);
+
+ // prepareGetActual sets the first day of week in the same week with
+ // the first day of a month. Unlike WEEK_OF_YEAR, week number for the
+ // week which contains days from both previous and current month is
+ // not unique. For example, last several days in the previous month
+ // is week 5, and the rest of week is week 1.
+ int32_t result = startValue;
+ if ((work->get(field, status) != startValue
+ && field != UCAL_WEEK_OF_MONTH && delta > 0 ) || U_FAILURE(status)) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "getActualHelper(fld %d) - got %d (not %d) - %s\n", field, work->get(field,status), startValue, u_errorName(status));
+#endif
+ } else {
+ do {
+ startValue += delta;
+ work->add(field, delta, status);
+ if (work->get(field, status) != startValue || U_FAILURE(status)) {
+#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;
+ }
+ result = startValue;
+ } while (startValue != endValue);
+ }
+ delete work;
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "getActualHelper(%d) = %d\n", field, result);
+#endif
+ return result;
+}
+
+
+
+
+// -------------------------------------
+
+void
+Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode& status)
+{
+
+ if (U_FAILURE(status)) return;
+
+ fFirstDayOfWeek = UCAL_SUNDAY;
+ fMinimalDaysInFirstWeek = 1;
+ fWeekendOnset = UCAL_SATURDAY;
+ fWeekendOnsetMillis = 0;
+ fWeekendCease = UCAL_SUNDAY;
+ fWeekendCeaseMillis = 86400000; // 24*60*60*1000
+
+ // Since week and weekend data is territory based instead of language based,
+ // we may need to tweak the locale that we are using to try to get the appropriate
+ // values, using the following logic:
+ // 1). If the locale has a language but no territory, use the territory as defined by
+ // the likely subtags.
+ // 2). If the locale has a script designation then we ignore it,
+ // then remove it ( i.e. "en_Latn_US" becomes "en_US" )
+
+ char minLocaleID[ULOC_FULLNAME_CAPACITY] = { 0 };
+ UErrorCode myStatus = U_ZERO_ERROR;
+
+ uloc_minimizeSubtags(desiredLocale.getName(),minLocaleID,ULOC_FULLNAME_CAPACITY,&myStatus);
+ Locale min = Locale::createFromName(minLocaleID);
+ Locale useLocale;
+ if ( uprv_strlen(desiredLocale.getCountry()) == 0 ||
+ (uprv_strlen(desiredLocale.getScript()) > 0 && uprv_strlen(min.getScript()) == 0) ) {
+ char maxLocaleID[ULOC_FULLNAME_CAPACITY] = { 0 };
+ myStatus = U_ZERO_ERROR;
+ uloc_addLikelySubtags(desiredLocale.getName(),maxLocaleID,ULOC_FULLNAME_CAPACITY,&myStatus);
+ Locale max = Locale::createFromName(maxLocaleID);
+ useLocale = Locale(max.getLanguage(),max.getCountry());
+ } else {
+ useLocale = Locale(desiredLocale);
+ }
+
+ /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to
+ a specific calendar, they aren't truly locale data. But this is the only place where valid and
+ actual locale can be set, so we take a shot at it here by loading a representative resource
+ from the calendar data. The code used to use the dateTimeElements resource to get first day
+ of week data, but this was moved to supplemental data under ticket 7755. (JCE) */
+
+ CalendarData calData(useLocale,type,status);
+ UResourceBundle *monthNames = calData.getByKey(gMonthNames,status);
+ if (U_SUCCESS(status)) {
+ U_LOCALE_BASED(locBased,*this);
+ locBased.setLocaleIDs(ures_getLocaleByType(monthNames, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(monthNames, ULOC_ACTUAL_LOCALE, &status));
+ } else {
+ status = U_USING_FALLBACK_WARNING;
+ return;
+ }
+
+
+ // Read week data values from supplementalData week data
+ UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);
+ ures_getByKey(rb, "weekData", rb, &status);
+ UResourceBundle *weekData = ures_getByKey(rb, useLocale.getCountry(), NULL, &status);
+ if (status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
+ status = U_ZERO_ERROR;
+ weekData = ures_getByKey(rb, "001", NULL, &status);
+ }
+
+ if (U_FAILURE(status)) {
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, " Failure loading weekData from supplemental = %s\n", u_errorName(status));
+#endif
+ status = U_USING_FALLBACK_WARNING;
+ } else {
+ int32_t arrLen;
+ const int32_t *weekDataArr = ures_getIntVector(weekData,&arrLen,&status);
+ if( U_SUCCESS(status) && arrLen == 6
+ && 1 <= weekDataArr[0] && weekDataArr[0] <= 7
+ && 1 <= weekDataArr[1] && weekDataArr[1] <= 7
+ && 1 <= weekDataArr[2] && weekDataArr[2] <= 7
+ && 1 <= weekDataArr[4] && weekDataArr[4] <= 7) {
+ fFirstDayOfWeek = (UCalendarDaysOfWeek)weekDataArr[0];
+ fMinimalDaysInFirstWeek = (uint8_t)weekDataArr[1];
+ fWeekendOnset = (UCalendarDaysOfWeek)weekDataArr[2];
+ fWeekendOnsetMillis = weekDataArr[3];
+ fWeekendCease = (UCalendarDaysOfWeek)weekDataArr[4];
+ fWeekendCeaseMillis = weekDataArr[5];
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ ures_close(weekData);
+ ures_close(rb);
+}
+
+/**
+* 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);
+}
+
+void
+Calendar::recalculateStamp() {
+ int32_t index;
+ int32_t currentValue;
+ int32_t j, i;
+
+ fNextStamp = 1;
+
+ for (j = 0; j < UCAL_FIELD_COUNT; j++) {
+ currentValue = STAMP_MAX;
+ index = -1;
+ for (i = 0; i < UCAL_FIELD_COUNT; i++) {
+ if (fStamp[i] > fNextStamp && fStamp[i] < currentValue) {
+ currentValue = fStamp[i];
+ index = i;
+ }
+ }
+
+ if (index >= 0) {
+ fStamp[index] = ++fNextStamp;
+ } else {
+ break;
+ }
+ }
+ fNextStamp++;
+}
+
+// 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-4.8.1/i18n/casetrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/casetrn.cpp
new file mode 100644
index 00000000000..5038c51da3d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/casetrn.cpp
@@ -0,0 +1,191 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2010, 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_ABSTRACT_RTTI_IMPLEMENTATION(CaseMapTransliterator)
+
+/**
+ * Constructs a transliterator.
+ */
+CaseMapTransliterator::CaseMapTransliterator(const UnicodeString &id, UCaseMapFull *map) :
+ Transliterator(id, 0),
+ fCsp(ucase_getSingleton()),
+ fMap(map)
+{
+ // 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-4.8.1/i18n/casetrn.h b/Build/source/libs/icu/icu-4.8.1/i18n/casetrn.h
new file mode 100644
index 00000000000..48233ccc3dc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/casetrn.h
@@ -0,0 +1,104 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2008, 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 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 = 0;
+
+ /**
+ * 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& 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-4.8.1/i18n/cecal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/cecal.cpp
new file mode 100644
index 00000000000..ab4eca97ef1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/cecal.cpp
@@ -0,0 +1,149 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003 - 2009, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "cecal.h"
+#include "gregoimp.h" //Math
+
+U_NAMESPACE_BEGIN
+
+static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 0, 0, 1, 1}, // ERA
+ { 1, 1, 5000000, 5000000}, // YEAR
+ { 0, 0, 12, 12}, // MONTH
+ { 1, 1, 52, 53}, // WEEK_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
+ { 1, 1, 5, 30}, // 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, 1, 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
+ { -5000000, -5000000, 5000000, 5000000}, // 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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
+};
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+CECalendar::CECalendar(const Locale& aLocale, UErrorCode& success)
+: Calendar(TimeZone::createDefault(), aLocale, success)
+{
+ setTimeInMillis(getNow(), success);
+}
+
+CECalendar::CECalendar (const CECalendar& other)
+: Calendar(other)
+{
+}
+
+CECalendar::~CECalendar()
+{
+}
+
+CECalendar&
+CECalendar::operator=(const CECalendar& right)
+{
+ Calendar::operator=(right);
+ return *this;
+}
+
+//-------------------------------------------------------------------------
+// Calendar framework
+//-------------------------------------------------------------------------
+
+int32_t
+CECalendar::handleComputeMonthStart(int32_t eyear,int32_t emonth, UBool /*useMonth*/) const
+{
+ return ceToJD(eyear, emonth, 0, getJDEpochOffset());
+}
+
+int32_t
+CECalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+ return LIMITS[field][limitType];
+}
+
+UBool
+CECalendar::inDaylightTime(UErrorCode& status) const
+{
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) {
+ return FALSE;
+ }
+
+ // Force an update of the state of the Calendar.
+ ((CECalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+UBool
+CECalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+//-------------------------------------------------------------------------
+// Calendar system Conversion methods...
+//-------------------------------------------------------------------------
+int32_t
+CECalendar::ceToJD(int32_t year, int32_t month, int32_t date, int32_t jdEpochOffset)
+{
+ // handle month > 12, < 0 (e.g. from add/set)
+ if ( month >= 0 ) {
+ year += month/13;
+ month %= 13;
+ } else {
+ ++month;
+ year += month/13 - 1;
+ month = month%13 + 12;
+ }
+ return (int32_t) (
+ jdEpochOffset // difference from Julian epoch to 1,1,1
+ + 365 * year // number of days from years
+ + ClockMath::floorDivide(year, 4) // extra day of leap year
+ + 30 * month // number of days from months (months are 0-based)
+ + date - 1 // number of days for present month (1 based)
+ );
+}
+
+void
+CECalendar::jdToCE(int32_t julianDay, int32_t jdEpochOffset, int32_t& year, int32_t& month, int32_t& day)
+{
+ int32_t c4; // number of 4 year cycle (1461 days)
+ int32_t r4; // remainder of 4 year cycle, always positive
+
+ c4 = ClockMath::floorDivide(julianDay - jdEpochOffset, 1461, r4);
+
+ year = 4 * c4 + (r4/365 - r4/1460); // 4 * <number of 4year cycle> + <years within the last cycle>
+
+ int32_t doy = (r4 == 1460) ? 365 : (r4 % 365); // days in present year
+
+ month = doy / 30; // 30 -> Coptic/Ethiopic month length up to 12th month
+ day = (doy % 30) + 1; // 1-based days in a month
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/cecal.h b/Build/source/libs/icu/icu-4.8.1/i18n/cecal.h
new file mode 100644
index 00000000000..471d88933e8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/cecal.h
@@ -0,0 +1,134 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef CECAL_H
+#define CECAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Base class for EthiopicCalendar and CopticCalendar.
+ * @internal
+ */
+class U_I18N_API CECalendar : public Calendar {
+
+protected:
+ //-------------------------------------------------------------------------
+ // Constructors...
+ //-------------------------------------------------------------------------
+
+ /**
+ * Constructs a CECalendar based on the current time in the default time zone
+ * with the given locale with the Julian epoch offiset
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of CECalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ CECalendar(const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ CECalendar (const CECalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~CECalendar();
+
+ /**
+ * Default assignment operator
+ * @param right Calendar object to be copied
+ * @internal
+ */
+ CECalendar& operator=(const CECalendar& right);
+
+protected:
+ //-------------------------------------------------------------------------
+ // Calendar framework
+ //-------------------------------------------------------------------------
+
+ /**
+ * Return JD of start of given month/extended year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const;
+
+ /**
+ * Calculate the limit for a specified type of limit and field
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) 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.
+ * @internal
+ */
+ virtual UBool inDaylightTime(UErrorCode&) const;
+
+ /**
+ * Returns TRUE because Coptic/Ethiopic Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+protected:
+ /**
+ * The Coptic and Ethiopic calendars differ only in their epochs.
+ * This method must be implemented by CECalendar subclasses to
+ * return the date offset from Julian
+ * @internal
+ */
+ virtual int32_t getJDEpochOffset() const = 0;
+
+ /**
+ * Convert an Coptic/Ethiopic year, month, and day to a Julian day.
+ *
+ * @param year the extended year
+ * @param month the month
+ * @param day the day
+ * @param jdEpochOffset the epoch offset from Julian epoch
+ * @return Julian day
+ * @internal
+ */
+ static int32_t ceToJD(int32_t year, int32_t month, int32_t date,
+ int32_t jdEpochOffset);
+
+ /**
+ * Convert a Julian day to an Coptic/Ethiopic year, month and day
+ *
+ * @param julianDay the Julian day
+ * @param jdEpochOffset the epoch offset from Julian epoch
+ * @param year receives the extended year
+ * @param month receives the month
+ * @param date receives the day
+ * @internal
+ */
+ static void jdToCE(int32_t julianDay, int32_t jdEpochOffset,
+ int32_t& year, int32_t& month, int32_t& day);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.cpp
new file mode 100644
index 00000000000..0f22812bde4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.cpp
@@ -0,0 +1,865 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2007-2008, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ******************************************************************************
+ *
+ * File CHNSECAL.CPP
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 9/18/2007 ajmacher ported from java ChineseCalendar
+ *****************************************************************************
+ */
+
+#include "chnsecal.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"
+
+// Debugging
+#ifdef U_DEBUG_CHNSECAL
+# include <stdio.h>
+# include <stdarg.h>
+static void debug_chnsecal_loc(const char *f, int32_t l)
+{
+ fprintf(stderr, "%s:%d: ", f, l);
+}
+
+static void debug_chnsecal_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_CHNSECAL_MSG(("four is: %d",4));
+#define U_DEBUG_CHNSECAL_MSG(x) {debug_chnsecal_loc(__FILE__,__LINE__);debug_chnsecal_msg x;}
+#else
+#define U_DEBUG_CHNSECAL_MSG(x)
+#endif
+
+
+// --- The cache --
+static UMTX astroLock = 0; // pod bay door lock
+static U_NAMESPACE_QUALIFIER CalendarAstronomer *gChineseCalendarAstro = NULL;
+static U_NAMESPACE_QUALIFIER CalendarCache *gChineseCalendarWinterSolsticeCache = NULL;
+static U_NAMESPACE_QUALIFIER CalendarCache *gChineseCalendarNewYearCache = NULL;
+
+/**
+ * The start year of the Chinese calendar, the 61st year of the reign
+ * of Huang Di. Some sources use the first year of his reign,
+ * resulting in EXTENDED_YEAR values 60 years greater and ERA (cycle)
+ * values one greater.
+ */
+static const int32_t CHINESE_EPOCH_YEAR = -2636; // Gregorian year
+
+/**
+ * The offset from GMT in milliseconds at which we perform astronomical
+ * computations. Some sources use a different historically accurate
+ * offset of GMT+7:45:40 for years before 1929; we do not do this.
+ */
+static const double CHINA_OFFSET = 8 * kOneHour;
+
+/**
+ * Value to be added or subtracted from the local days of a new moon to
+ * get close to the next or prior new moon, but not cross it. Must be
+ * >= 1 and < CalendarAstronomer.SYNODIC_MONTH.
+ */
+static const int32_t SYNODIC_GAP = 25;
+
+
+U_CDECL_BEGIN
+static UBool calendar_chinese_cleanup(void) {
+ if (gChineseCalendarAstro) {
+ delete gChineseCalendarAstro;
+ gChineseCalendarAstro = NULL;
+ }
+ if (gChineseCalendarWinterSolsticeCache) {
+ delete gChineseCalendarWinterSolsticeCache;
+ gChineseCalendarWinterSolsticeCache = NULL;
+ }
+ if (gChineseCalendarNewYearCache) {
+ delete gChineseCalendarNewYearCache;
+ gChineseCalendarNewYearCache = NULL;
+ }
+ umtx_destroy(&astroLock);
+ return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+
+// Implementation of the ChineseCalendar class
+
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+
+Calendar* ChineseCalendar::clone() const {
+ return new ChineseCalendar(*this);
+}
+
+ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success)
+: Calendar(TimeZone::createDefault(), aLocale, success)
+{
+ isLeapYear = FALSE;
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+ChineseCalendar::ChineseCalendar(const ChineseCalendar& other) : Calendar(other) {
+ isLeapYear = other.isLeapYear;
+}
+
+ChineseCalendar::~ChineseCalendar()
+{
+}
+
+const char *ChineseCalendar::getType() const {
+ return "chinese";
+}
+
+//-------------------------------------------------------------------------
+// Minimum / Maximum access functions
+//-------------------------------------------------------------------------
+
+
+static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 1, 1, 83333, 83333}, // ERA
+ { 1, 1, 60, 60}, // YEAR
+ { 0, 0, 11, 11}, // MONTH
+ { 1, 1, 50, 55}, // WEEK_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // 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
+ { -5000000, -5000000, 5000000, 5000000}, // 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
+ { 0, 0, 1, 1}, // IS_LEAP_MONTH
+};
+
+
+/**
+* @draft ICU 2.4
+*/
+int32_t ChineseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
+ return LIMITS[field][limitType];
+}
+
+
+//----------------------------------------------------------------------
+// Calendar framework
+//----------------------------------------------------------------------
+
+/**
+ * Implement abstract Calendar method to return the extended year
+ * defined by the current fields. This will use either the ERA and
+ * YEAR field as the cycle and year-of-cycle, or the EXTENDED_YEAR
+ * field as the continuous year count, depending on which is newer.
+ * @stable ICU 2.8
+ */
+int32_t ChineseCalendar::handleGetExtendedYear() {
+ int32_t year;
+ if (newestStamp(UCAL_ERA, UCAL_YEAR, kUnset) <= fStamp[UCAL_EXTENDED_YEAR]) {
+ year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else {
+ int32_t cycle = internalGet(UCAL_ERA, 1) - 1; // 0-based cycle
+ year = cycle * 60 + internalGet(UCAL_YEAR, 1);
+ }
+ return year;
+}
+
+/**
+ * Override Calendar method to return the number of days in the given
+ * extended year and month.
+ *
+ * <p>Note: This method also reads the IS_LEAP_MONTH field to determine
+ * whether or not the given month is a leap month.
+ * @stable ICU 2.8
+ */
+int32_t ChineseCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
+ int32_t thisStart = handleComputeMonthStart(extendedYear, month, TRUE) -
+ kEpochStartAsJulianDay + 1; // Julian day -> local days
+ int32_t nextStart = newMoonNear(thisStart + SYNODIC_GAP, TRUE);
+ return nextStart - thisStart;
+}
+
+/**
+ * Override Calendar to compute several fields specific to the Chinese
+ * 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.
+ *
+ * <p>Compute the ChineseCalendar-specific field IS_LEAP_MONTH.
+ * @stable ICU 2.8
+ */
+void ChineseCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/) {
+
+ computeChineseFields(julianDay - kEpochStartAsJulianDay, // local days
+ getGregorianYear(), getGregorianMonth(),
+ TRUE); // set all fields
+}
+
+/**
+ * Field resolution table that incorporates IS_LEAP_MONTH.
+ */
+const UFieldResolutionTable ChineseCalendar::CHINESE_DATE_PRECEDENCE[] =
+{
+ {
+ { 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_IS_LEAP_MONTH, kResolveSTOP },
+ { 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}}
+};
+
+/**
+ * Override Calendar to add IS_LEAP_MONTH to the field resolution
+ * table.
+ * @stable ICU 2.8
+ */
+const UFieldResolutionTable* ChineseCalendar::getFieldResolutionTable() const {
+ return CHINESE_DATE_PRECEDENCE;
+}
+
+/**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year.
+ *
+ * <p>Note: This method reads the IS_LEAP_MONTH field to determine
+ * whether the given month is a leap month.
+ * @param eyear the extended year
+ * @param month the zero-based month. The month is also determined
+ * by reading the IS_LEAP_MONTH field.
+ * @return the Julian day number of the day before the first
+ * day of the given month and year
+ * @stable ICU 2.8
+ */
+int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const {
+
+ ChineseCalendar *nonConstThis = (ChineseCalendar*)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) {
+ double m = month;
+ eyear += (int32_t)ClockMath::floorDivide(m, 12.0, m);
+ month = (int32_t)m;
+ }
+
+ int32_t gyear = eyear + CHINESE_EPOCH_YEAR - 1; // Gregorian year
+ int32_t theNewYear = newYear(gyear);
+ int32_t newMoon = newMoonNear(theNewYear + month * 29, TRUE);
+
+ int32_t julianDay = newMoon + kEpochStartAsJulianDay;
+
+ // Save fields for later restoration
+ int32_t saveMonth = internalGet(UCAL_MONTH);
+ int32_t saveIsLeapMonth = internalGet(UCAL_IS_LEAP_MONTH);
+
+ // Ignore IS_LEAP_MONTH field if useMonth is false
+ int32_t isLeapMonth = useMonth ? saveIsLeapMonth : 0;
+
+ UErrorCode status = U_ZERO_ERROR;
+ nonConstThis->computeGregorianFields(julianDay, status);
+ if (U_FAILURE(status))
+ return 0;
+
+ // This will modify the MONTH and IS_LEAP_MONTH fields (only)
+ nonConstThis->computeChineseFields(newMoon, getGregorianYear(),
+ getGregorianMonth(), FALSE);
+
+ if (month != internalGet(UCAL_MONTH) ||
+ isLeapMonth != internalGet(UCAL_IS_LEAP_MONTH)) {
+ newMoon = newMoonNear(newMoon + SYNODIC_GAP, TRUE);
+ julianDay = newMoon + kEpochStartAsJulianDay;
+ }
+
+ nonConstThis->internalSet(UCAL_MONTH, saveMonth);
+ nonConstThis->internalSet(UCAL_IS_LEAP_MONTH, saveIsLeapMonth);
+
+ return julianDay - 1;
+}
+
+
+/**
+ * Override Calendar to handle leap months properly.
+ * @stable ICU 2.8
+ */
+void ChineseCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status) {
+ switch (field) {
+ case UCAL_MONTH:
+ if (amount != 0) {
+ int32_t dom = get(UCAL_DAY_OF_MONTH, status);
+ if (U_FAILURE(status)) break;
+ int32_t day = get(UCAL_JULIAN_DAY, status) - kEpochStartAsJulianDay; // Get local day
+ if (U_FAILURE(status)) break;
+ int32_t moon = day - dom + 1; // New moon
+ offsetMonth(moon, dom, amount);
+ }
+ break;
+ default:
+ Calendar::add(field, amount, status);
+ break;
+ }
+}
+
+/**
+ * Override Calendar to handle leap months properly.
+ * @stable ICU 2.8
+ */
+void ChineseCalendar::add(EDateFields field, int32_t amount, UErrorCode& status) {
+ add((UCalendarDateFields)field, amount, status);
+}
+
+/**
+ * Override Calendar to handle leap months properly.
+ * @stable ICU 2.8
+ */
+void ChineseCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) {
+ switch (field) {
+ case UCAL_MONTH:
+ if (amount != 0) {
+ int32_t dom = get(UCAL_DAY_OF_MONTH, status);
+ if (U_FAILURE(status)) break;
+ int32_t day = get(UCAL_JULIAN_DAY, status) - kEpochStartAsJulianDay; // Get local day
+ if (U_FAILURE(status)) break;
+ int32_t moon = day - dom + 1; // New moon (start of this month)
+
+ // Note throughout the following: Months 12 and 1 are never
+ // followed by a leap month (D&R p. 185).
+
+ // Compute the adjusted month number m. This is zero-based
+ // value from 0..11 in a non-leap year, and from 0..12 in a
+ // leap year.
+ int32_t m = get(UCAL_MONTH, status); // 0-based month
+ if (U_FAILURE(status)) break;
+ if (isLeapYear) { // (member variable)
+ if (get(UCAL_IS_LEAP_MONTH, status) == 1) {
+ ++m;
+ } else {
+ // Check for a prior leap month. (In the
+ // following, month 0 is the first month of the
+ // year.) Month 0 is never followed by a leap
+ // month, and we know month m is not a leap month.
+ // moon1 will be the start of month 0 if there is
+ // no leap month between month 0 and month m;
+ // otherwise it will be the start of month 1.
+ int moon1 = moon -
+ (int) (CalendarAstronomer::SYNODIC_MONTH * (m - 0.5));
+ moon1 = newMoonNear(moon1, TRUE);
+ if (isLeapMonthBetween(moon1, moon)) {
+ ++m;
+ }
+ }
+ if (U_FAILURE(status)) break;
+ }
+
+ // Now do the standard roll computation on m, with the
+ // allowed range of 0..n-1, where n is 12 or 13.
+ int32_t n = isLeapYear ? 13 : 12; // Months in this year
+ int32_t newM = (m + amount) % n;
+ if (newM < 0) {
+ newM += n;
+ }
+
+ if (newM != m) {
+ offsetMonth(moon, dom, newM - m);
+ }
+ }
+ break;
+ default:
+ Calendar::roll(field, amount, status);
+ break;
+ }
+}
+
+void ChineseCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
+ roll((UCalendarDateFields)field, amount, status);
+}
+
+
+//------------------------------------------------------------------
+// Support methods and constants
+//------------------------------------------------------------------
+
+/**
+ * Convert local days to UTC epoch milliseconds.
+ * @param days days after January 1, 1970 0:00 Asia/Shanghai
+ * @return milliseconds after January 1, 1970 0:00 GMT
+ */
+double ChineseCalendar::daysToMillis(double days) {
+ return (days * kOneDay) - CHINA_OFFSET;
+}
+
+/**
+ * Convert UTC epoch milliseconds to local days.
+ * @param millis milliseconds after January 1, 1970 0:00 GMT
+ * @return days after January 1, 1970 0:00 Asia/Shanghai
+ */
+double ChineseCalendar::millisToDays(double millis) {
+ return ClockMath::floorDivide(millis + CHINA_OFFSET, kOneDay);
+}
+
+//------------------------------------------------------------------
+// Astronomical computations
+//------------------------------------------------------------------
+
+
+/**
+ * Return the major solar term on or after December 15 of the given
+ * Gregorian year, that is, the winter solstice of the given year.
+ * Computations are relative to Asia/Shanghai time zone.
+ * @param gyear a Gregorian year
+ * @return days after January 1, 1970 0:00 Asia/Shanghai of the
+ * winter solstice of the given year
+ */
+int32_t ChineseCalendar::winterSolstice(int32_t gyear) const {
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t cacheValue = CalendarCache::get(&gChineseCalendarWinterSolsticeCache, gyear, status);
+
+ if (cacheValue == 0) {
+ // In books December 15 is used, but it fails for some years
+ // using our algorithms, e.g.: 1298 1391 1492 1553 1560. That
+ // is, winterSolstice(1298) starts search at Dec 14 08:00:00
+ // PST 1298 with a final result of Dec 14 10:31:59 PST 1299.
+ double ms = daysToMillis(Grego::fieldsToDay(gyear, UCAL_DECEMBER, 1));
+
+ umtx_lock(&astroLock);
+ if(gChineseCalendarAstro == NULL) {
+ gChineseCalendarAstro = new CalendarAstronomer();
+ ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
+ }
+ gChineseCalendarAstro->setTime(ms);
+ UDate solarLong = gChineseCalendarAstro->getSunTime(CalendarAstronomer::WINTER_SOLSTICE(), TRUE);
+ umtx_unlock(&astroLock);
+
+ // Winter solstice is 270 degrees solar longitude aka Dongzhi
+ cacheValue = (int32_t)millisToDays(solarLong);
+ CalendarCache::put(&gChineseCalendarWinterSolsticeCache, gyear, cacheValue, status);
+ }
+ if(U_FAILURE(status)) {
+ cacheValue = 0;
+ }
+ return cacheValue;
+}
+
+/**
+ * Return the closest new moon to the given date, searching either
+ * forward or backward in time.
+ * @param days days after January 1, 1970 0:00 Asia/Shanghai
+ * @param after if true, search for a new moon on or after the given
+ * date; otherwise, search for a new moon before it
+ * @return days after January 1, 1970 0:00 Asia/Shanghai of the nearest
+ * new moon after or before <code>days</code>
+ */
+int32_t ChineseCalendar::newMoonNear(double days, UBool after) const {
+
+ umtx_lock(&astroLock);
+ if(gChineseCalendarAstro == NULL) {
+ gChineseCalendarAstro = new CalendarAstronomer();
+ ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
+ }
+ gChineseCalendarAstro->setTime(daysToMillis(days));
+ UDate newMoon = gChineseCalendarAstro->getMoonTime(CalendarAstronomer::NEW_MOON(), after);
+ umtx_unlock(&astroLock);
+
+ return (int32_t) millisToDays(newMoon);
+}
+
+/**
+ * Return the nearest integer number of synodic months between
+ * two dates.
+ * @param day1 days after January 1, 1970 0:00 Asia/Shanghai
+ * @param day2 days after January 1, 1970 0:00 Asia/Shanghai
+ * @return the nearest integer number of months between day1 and day2
+ */
+int32_t ChineseCalendar::synodicMonthsBetween(int32_t day1, int32_t day2) const {
+ double roundme = ((day2 - day1) / CalendarAstronomer::SYNODIC_MONTH);
+ return (int32_t) (roundme + (roundme >= 0 ? .5 : -.5));
+}
+
+/**
+ * Return the major solar term on or before a given date. This
+ * will be an integer from 1..12, with 1 corresponding to 330 degrees,
+ * 2 to 0 degrees, 3 to 30 degrees,..., and 12 to 300 degrees.
+ * @param days days after January 1, 1970 0:00 Asia/Shanghai
+ */
+int32_t ChineseCalendar::majorSolarTerm(int32_t days) const {
+
+ umtx_lock(&astroLock);
+ if(gChineseCalendarAstro == NULL) {
+ gChineseCalendarAstro = new CalendarAstronomer();
+ ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
+ }
+ gChineseCalendarAstro->setTime(daysToMillis(days));
+ UDate solarLongitude = gChineseCalendarAstro->getSunLongitude();
+ umtx_unlock(&astroLock);
+
+ // Compute (floor(solarLongitude / (pi/6)) + 2) % 12
+ int32_t term = ( ((int32_t)(6 * solarLongitude / CalendarAstronomer::PI)) + 2 ) % 12;
+ if (term < 1) {
+ term += 12;
+ }
+ return term;
+}
+
+/**
+ * Return true if the given month lacks a major solar term.
+ * @param newMoon days after January 1, 1970 0:00 Asia/Shanghai of a new
+ * moon
+ */
+UBool ChineseCalendar::hasNoMajorSolarTerm(int32_t newMoon) const {
+ return majorSolarTerm(newMoon) ==
+ majorSolarTerm(newMoonNear(newMoon + SYNODIC_GAP, TRUE));
+}
+
+
+//------------------------------------------------------------------
+// Time to fields
+//------------------------------------------------------------------
+
+/**
+ * Return true if there is a leap month on or after month newMoon1 and
+ * at or before month newMoon2.
+ * @param newMoon1 days after January 1, 1970 0:00 Asia/Shanghai of a
+ * new moon
+ * @param newMoon2 days after January 1, 1970 0:00 Asia/Shanghai of a
+ * new moon
+ */
+UBool ChineseCalendar::isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) const {
+
+#ifdef U_DEBUG_CHNSECAL
+ // This is only needed to debug the timeOfAngle divergence bug.
+ // Remove this later. Liu 11/9/00
+ if (synodicMonthsBetween(newMoon1, newMoon2) >= 50) {
+ U_DEBUG_CHNSECAL_MSG((
+ "isLeapMonthBetween(%d, %d): Invalid parameters", newMoon1, newMoon2
+ ));
+ }
+#endif
+
+ return (newMoon2 >= newMoon1) &&
+ (isLeapMonthBetween(newMoon1, newMoonNear(newMoon2 - SYNODIC_GAP, FALSE)) ||
+ hasNoMajorSolarTerm(newMoon2));
+}
+
+/**
+ * Compute fields for the Chinese calendar system. This method can
+ * either set all relevant fields, as required by
+ * <code>handleComputeFields()</code>, or it can just set the MONTH and
+ * IS_LEAP_MONTH fields, as required by
+ * <code>handleComputeMonthStart()</code>.
+ *
+ * <p>As a side effect, this method sets {@link #isLeapYear}.
+ * @param days days after January 1, 1970 0:00 Asia/Shanghai of the
+ * date to compute fields for
+ * @param gyear the Gregorian year of the given date
+ * @param gmonth the Gregorian month of the given date
+ * @param setAllFields if true, set the EXTENDED_YEAR, ERA, YEAR,
+ * DAY_OF_MONTH, and DAY_OF_YEAR fields. In either case set the MONTH
+ * and IS_LEAP_MONTH fields.
+ */
+void ChineseCalendar::computeChineseFields(int32_t days, int32_t gyear, int32_t gmonth,
+ UBool setAllFields) {
+
+ // Find the winter solstices before and after the target date.
+ // These define the boundaries of this Chinese year, specifically,
+ // the position of month 11, which always contains the solstice.
+ // We want solsticeBefore <= date < solsticeAfter.
+ int32_t solsticeBefore;
+ int32_t solsticeAfter = winterSolstice(gyear);
+ if (days < solsticeAfter) {
+ solsticeBefore = winterSolstice(gyear - 1);
+ } else {
+ solsticeBefore = solsticeAfter;
+ solsticeAfter = winterSolstice(gyear + 1);
+ }
+
+ // Find the start of the month after month 11. This will be either
+ // the prior month 12 or leap month 11 (very rare). Also find the
+ // start of the following month 11.
+ int32_t firstMoon = newMoonNear(solsticeBefore + 1, TRUE);
+ int32_t lastMoon = newMoonNear(solsticeAfter + 1, FALSE);
+ int32_t thisMoon = newMoonNear(days + 1, FALSE); // Start of this month
+ // Note: isLeapYear is a member variable
+ isLeapYear = synodicMonthsBetween(firstMoon, lastMoon) == 12;
+
+ int32_t month = synodicMonthsBetween(firstMoon, thisMoon);
+ if (isLeapYear && isLeapMonthBetween(firstMoon, thisMoon)) {
+ month--;
+ }
+ if (month < 1) {
+ month += 12;
+ }
+
+ UBool isLeapMonth = isLeapYear &&
+ hasNoMajorSolarTerm(thisMoon) &&
+ !isLeapMonthBetween(firstMoon, newMoonNear(thisMoon - SYNODIC_GAP, FALSE));
+
+ internalSet(UCAL_MONTH, month-1); // Convert from 1-based to 0-based
+ internalSet(UCAL_IS_LEAP_MONTH, isLeapMonth?1:0);
+
+ if (setAllFields) {
+
+ int32_t year = gyear - CHINESE_EPOCH_YEAR;
+ if (month < 11 ||
+ gmonth >= UCAL_JULY) {
+ year++;
+ }
+ int32_t dayOfMonth = days - thisMoon + 1;
+
+ internalSet(UCAL_EXTENDED_YEAR, year);
+
+ // 0->0,60 1->1,1 60->1,60 61->2,1 etc.
+ int32_t yearOfCycle;
+ int32_t cycle = ClockMath::floorDivide(year - 1, 60, yearOfCycle);
+ internalSet(UCAL_ERA, cycle + 1);
+ internalSet(UCAL_YEAR, yearOfCycle + 1);
+
+ internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
+
+ // Days will be before the first new year we compute if this
+ // date is in month 11, leap 11, 12. There is never a leap 12.
+ // New year computations are cached so this should be cheap in
+ // the long run.
+ int32_t theNewYear = newYear(gyear);
+ if (days < theNewYear) {
+ theNewYear = newYear(gyear-1);
+ }
+ internalSet(UCAL_DAY_OF_YEAR, days - theNewYear + 1);
+ }
+}
+
+
+//------------------------------------------------------------------
+// Fields to time
+//------------------------------------------------------------------
+
+/**
+ * Return the Chinese new year of the given Gregorian year.
+ * @param gyear a Gregorian year
+ * @return days after January 1, 1970 0:00 Asia/Shanghai of the
+ * Chinese new year of the given year (this will be a new moon)
+ */
+int32_t ChineseCalendar::newYear(int32_t gyear) const {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t cacheValue = CalendarCache::get(&gChineseCalendarNewYearCache, gyear, status);
+
+ if (cacheValue == 0) {
+
+ int32_t solsticeBefore= winterSolstice(gyear - 1);
+ int32_t solsticeAfter = winterSolstice(gyear);
+ int32_t newMoon1 = newMoonNear(solsticeBefore + 1, TRUE);
+ int32_t newMoon2 = newMoonNear(newMoon1 + SYNODIC_GAP, TRUE);
+ int32_t newMoon11 = newMoonNear(solsticeAfter + 1, FALSE);
+
+ if (synodicMonthsBetween(newMoon1, newMoon11) == 12 &&
+ (hasNoMajorSolarTerm(newMoon1) || hasNoMajorSolarTerm(newMoon2))) {
+ cacheValue = newMoonNear(newMoon2 + SYNODIC_GAP, TRUE);
+ } else {
+ cacheValue = newMoon2;
+ }
+
+ CalendarCache::put(&gChineseCalendarNewYearCache, gyear, cacheValue, status);
+ }
+ if(U_FAILURE(status)) {
+ cacheValue = 0;
+ }
+ return cacheValue;
+}
+
+/**
+ * Adjust this calendar to be delta months before or after a given
+ * start position, pinning the day of month if necessary. The start
+ * position is given as a local days number for the start of the month
+ * and a day-of-month. Used by add() and roll().
+ * @param newMoon the local days of the first day of the month of the
+ * start position (days after January 1, 1970 0:00 Asia/Shanghai)
+ * @param dom the 1-based day-of-month of the start position
+ * @param delta the number of months to move forward or backward from
+ * the start position
+ */
+void ChineseCalendar::offsetMonth(int32_t newMoon, int32_t dom, int32_t delta) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Move to the middle of the month before our target month.
+ newMoon += (int32_t) (CalendarAstronomer::SYNODIC_MONTH * (delta - 0.5));
+
+ // Search forward to the target month's new moon
+ newMoon = newMoonNear(newMoon, TRUE);
+
+ // Find the target dom
+ int32_t jd = newMoon + kEpochStartAsJulianDay - 1 + dom;
+
+ // Pin the dom. In this calendar all months are 29 or 30 days
+ // so pinning just means handling dom 30.
+ if (dom > 29) {
+ set(UCAL_JULIAN_DAY, jd-1);
+ // TODO Fix this. We really shouldn't ever have to
+ // explicitly call complete(). This is either a bug in
+ // this method, in ChineseCalendar, or in
+ // Calendar.getActualMaximum(). I suspect the last.
+ complete(status);
+ if (U_FAILURE(status)) return;
+ if (getActualMaximum(UCAL_DAY_OF_MONTH, status) >= dom) {
+ if (U_FAILURE(status)) return;
+ set(UCAL_JULIAN_DAY, jd);
+ }
+ } else {
+ set(UCAL_JULIAN_DAY, jd);
+ }
+}
+
+
+UBool
+ChineseCalendar::inDaylightTime(UErrorCode& status) const
+{
+ // copied from GregorianCalendar
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
+ return FALSE;
+
+ // Force an update of the state of the Calendar.
+ ((ChineseCalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+// default century
+const UDate ChineseCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t ChineseCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate ChineseCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t ChineseCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool ChineseCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate ChineseCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t ChineseCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+ChineseCalendar::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
+ChineseCalendar::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
+ChineseCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ UErrorCode status = U_ZERO_ERROR;
+ ChineseCalendar calendar(Locale("@calendar=chinese"),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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ umtx_unlock(NULL);
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChineseCalendar)
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.h b/Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.h
new file mode 100644
index 00000000000..d379770e174
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/chnsecal.h
@@ -0,0 +1,294 @@
+/*
+ *****************************************************************************
+ * Copyright (C) 2007-2008, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ *****************************************************************************
+ *
+ * File CHNSECAL.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 9/18/2007 ajmacher ported from java ChineseCalendar
+ *****************************************************************************
+ */
+
+#ifndef CHNSECAL_H
+#define CHNSECAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>ChineseCalendar</code> is a concrete subclass of {@link Calendar}
+ * that implements a traditional Chinese calendar. The traditional Chinese
+ * calendar is a lunisolar calendar: Each month starts on a new moon, and
+ * the months are numbered according to solar events, specifically, to
+ * guarantee that month 11 always contains the winter solstice. In order
+ * to accomplish this, leap months are inserted in certain years. Leap
+ * months are numbered the same as the month they follow. The decision of
+ * which month is a leap month depends on the relative movements of the sun
+ * and moon.
+ *
+ * <p>This class defines one addition field beyond those defined by
+ * <code>Calendar</code>: The <code>IS_LEAP_MONTH</code> field takes the
+ * value of 0 for normal months, or 1 for leap months.
+ *
+ * <p>All astronomical computations are performed with respect to a time
+ * zone of GMT+8:00 and a longitude of 120 degrees east. Although some
+ * calendars implement a historically more accurate convention of using
+ * Beijing's local longitude (116 degrees 25 minutes east) and time zone
+ * (GMT+7:45:40) for dates before 1929, we do not implement this here.
+ *
+ * <p>Years are counted in two different ways in the Chinese calendar. The
+ * first method is by sequential numbering from the 61st year of the reign
+ * of Huang Di, 2637 BCE, which is designated year 1 on the Chinese
+ * calendar. The second method uses 60-year cycles from the same starting
+ * point, which is designated year 1 of cycle 1. In this class, the
+ * <code>EXTENDED_YEAR</code> field contains the sequential year count.
+ * The <code>ERA</code> field contains the cycle number, and the
+ * <code>YEAR</code> field contains the year of the cycle, a value between
+ * 1 and 60.
+ *
+ * <p>There is some variation in what is considered the starting point of
+ * the calendar, with some sources starting in the first year of the reign
+ * of Huang Di, rather than the 61st. This gives continuous year numbers
+ * 60 years greater and cycle numbers one greater than what this class
+ * implements.
+ *
+ * <p>Because <code>ChineseCalendar</code> defines an additional field and
+ * redefines the way the <code>ERA</code> field is used, it requires a new
+ * format class, <code>ChineseDateFormat</code>. As always, use the
+ * methods <code>DateFormat.getXxxInstance(Calendar cal,...)</code> to
+ * obtain a formatter for this calendar.
+ *
+ * <p>References:<ul>
+ *
+ * <li>Dershowitz and Reingold, <i>Calendrical Calculations</i>,
+ * Cambridge University Press, 1997</li>
+ *
+ * <li>Helmer Aslaksen's
+ * <a href="http://www.math.nus.edu.sg/aslaksen/calendar/chinese.shtml">
+ * Chinese Calendar page</a></li>
+ *
+ * <li>The <a href="http://www.tondering.dk/claus/calendar.html">
+ * Calendar FAQ</a></li>
+ *
+ * </ul>
+ *
+ * <p>
+ * This class should not be subclassed.</p>
+ * <p>
+ * ChineseCalendar usually should be instantiated using
+ * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
+ * with the tag <code>"@calendar=chinese"</code>.</p>
+ *
+ * @see com.ibm.icu.text.ChineseDateFormat
+ * @see com.ibm.icu.util.Calendar
+ * @author Alan Liu
+ * @stable ICU 2.8
+ */
+class ChineseCalendar : public Calendar {
+ public:
+ //-------------------------------------------------------------------------
+ // Constructors...
+ //-------------------------------------------------------------------------
+
+ /**
+ * Constructs an ChineseCalendar 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 ChineseCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ ChineseCalendar(const Locale& aLocale, UErrorCode &success);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ ChineseCalendar(const ChineseCalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~ChineseCalendar();
+
+ // clone
+ virtual Calendar* clone() const;
+
+ private:
+
+ //-------------------------------------------------------------------------
+ // Internal data....
+ //-------------------------------------------------------------------------
+
+ UBool isLeapYear;
+
+ //----------------------------------------------------------------------
+ // Calendar framework
+ //----------------------------------------------------------------------
+
+ protected:
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const;
+ virtual int32_t handleGetExtendedYear();
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+ virtual const UFieldResolutionTable* getFieldResolutionTable() const;
+
+
+
+public:
+ virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status);
+ virtual void add(EDateFields field, int32_t amount, UErrorCode &status);
+ virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status);
+ virtual void roll(EDateFields field, int32_t amount, UErrorCode &status);
+
+
+ //----------------------------------------------------------------------
+ // Internal methods & astronomical calculations
+ //----------------------------------------------------------------------
+
+private:
+
+ static const UFieldResolutionTable CHINESE_DATE_PRECEDENCE[];
+
+ static double daysToMillis(double days);
+ static double millisToDays(double millis);
+ virtual int32_t winterSolstice(int32_t gyear) const;
+ virtual int32_t newMoonNear(double days, UBool after) const;
+ virtual int32_t synodicMonthsBetween(int32_t day1, int32_t day2) const;
+ virtual int32_t majorSolarTerm(int32_t days) const;
+ virtual UBool hasNoMajorSolarTerm(int32_t newMoon) const;
+ virtual UBool isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) const;
+ virtual void computeChineseFields(int32_t days, int32_t gyear,
+ int32_t gmonth, UBool setAllFields);
+ virtual int32_t newYear(int32_t gyear) const;
+ virtual void offsetMonth(int32_t newMoon, int32_t dom, int32_t delta);
+
+
+ // 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, "chinese".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() 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 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);
+
+ ChineseCalendar(); // default constructor not implemented
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
+
+
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/choicfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/choicfmt.cpp
new file mode 100644
index 00000000000..58b440a7e4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/choicfmt.cpp
@@ -0,0 +1,598 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 "messageimpl.h"
+#include "putilimp.h"
+#include "uassert.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) /*-*/
+
+static const UChar LEFT_CURLY_BRACE = 0x7B; /*{*/
+static const UChar RIGHT_CURLY_BRACE = 0x7D; /*}*/
+
+#ifdef INFINITY
+#undef INFINITY
+#endif
+#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)
+: constructorErrorCode(status),
+ msgPattern(status)
+{
+ 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 )
+: constructorErrorCode(U_ZERO_ERROR),
+ msgPattern(constructorErrorCode)
+{
+ setChoices(limits, NULL, formats, cnt, constructorErrorCode);
+}
+
+// -------------------------------------
+
+ChoiceFormat::ChoiceFormat(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t cnt )
+: constructorErrorCode(U_ZERO_ERROR),
+ msgPattern(constructorErrorCode)
+{
+ setChoices(limits, closures, formats, cnt, constructorErrorCode);
+}
+
+// -------------------------------------
+// copy constructor
+
+ChoiceFormat::ChoiceFormat(const ChoiceFormat& that)
+: NumberFormat(that),
+ constructorErrorCode(that.constructorErrorCode),
+ msgPattern(that.msgPattern)
+{
+}
+
+// -------------------------------------
+// Private constructor that creates a
+// ChoiceFormat instance based on the
+// pattern and populates UParseError
+
+ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
+ UParseError& parseError,
+ UErrorCode& status)
+: constructorErrorCode(status),
+ msgPattern(status)
+{
+ 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;
+ return msgPattern == thatAlias.msgPattern;
+}
+
+// -------------------------------------
+// copy constructor
+
+const ChoiceFormat&
+ChoiceFormat::operator=(const ChoiceFormat& that)
+{
+ if (this != &that) {
+ NumberFormat::operator=(that);
+ constructorErrorCode = that.constructorErrorCode;
+ msgPattern = that.msgPattern;
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+ChoiceFormat::~ChoiceFormat()
+{
+}
+
+// -------------------------------------
+
+/**
+ * Convert a double value to a string without the overhead of NumberFormat.
+ */
+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 *expPtr;
+
+ sprintf(temp, "%.*g", 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 != 0 && *itrPtr != 'e') {
+ /* We reached something that looks like a decimal point.
+ In case someone used setlocale(), which changes the decimal point. */
+ *itrPtr = '.';
+ itrPtr++;
+ }
+ /* Search for the exponent */
+ while (*itrPtr && *itrPtr != 'e') {
+ itrPtr++;
+ }
+ if (*itrPtr == 'e') {
+ itrPtr++;
+ /* Verify the exponent sign */
+ if (*itrPtr == '+' || *itrPtr == '-') {
+ itrPtr++;
+ }
+ /* Remove leading zeros. You will see this on Windows machines. */
+ expPtr = itrPtr;
+ while (*itrPtr == '0') {
+ itrPtr++;
+ }
+ if (*itrPtr && expPtr != itrPtr) {
+ /* Shift the exponent without zeros. */
+ while (*itrPtr) {
+ *(expPtr++) = *(itrPtr++);
+ }
+ // NULL terminate
+ *expPtr = 0;
+ }
+ }
+
+ string = UnicodeString(temp, -1, US_INV); /* invariant codepage */
+ return string;
+}
+
+// -------------------------------------
+// calls the overloaded applyPattern method.
+
+void
+ChoiceFormat::applyPattern(const UnicodeString& pattern,
+ UErrorCode& status)
+{
+ msgPattern.parseChoiceStyle(pattern, NULL, status);
+ constructorErrorCode = status;
+}
+
+// -------------------------------------
+// Applies the pattern to this ChoiceFormat instance.
+
+void
+ChoiceFormat::applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ msgPattern.parseChoiceStyle(pattern, &parseError, status);
+ constructorErrorCode = status;
+}
+// -------------------------------------
+// Returns the input pattern string.
+
+UnicodeString&
+ChoiceFormat::toPattern(UnicodeString& result) const
+{
+ return result = msgPattern.getPatternString();
+}
+
+// -------------------------------------
+// Sets the limit and format arrays.
+void
+ChoiceFormat::setChoices( const double* limits,
+ const UnicodeString* formats,
+ int32_t cnt )
+{
+ UErrorCode errorCode = U_ZERO_ERROR;
+ setChoices(limits, NULL, formats, cnt, errorCode);
+}
+
+// -------------------------------------
+// Sets the limit and format arrays.
+void
+ChoiceFormat::setChoices( const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t cnt )
+{
+ UErrorCode errorCode = U_ZERO_ERROR;
+ setChoices(limits, closures, formats, cnt, errorCode);
+}
+
+void
+ChoiceFormat::setChoices(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t count,
+ UErrorCode &errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ if (limits == NULL || formats == NULL) {
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ // Reconstruct the original input pattern.
+ // Modified version of the pre-ICU 4.8 toPattern() implementation.
+ UnicodeString result;
+ for (int32_t i = 0; i < count; ++i) {
+ if (i != 0) {
+ result += VERTICAL_BAR;
+ }
+ UnicodeString buf;
+ if (uprv_isPositiveInfinity(limits[i])) {
+ result += INFINITY;
+ } else if (uprv_isNegativeInfinity(limits[i])) {
+ result += MINUS;
+ result += INFINITY;
+ } else {
+ result += dtos(limits[i], buf);
+ }
+ if (closures != NULL && closures[i]) {
+ result += LESS_THAN;
+ } else {
+ result += LESS_EQUAL;
+ }
+ // Append formats[i], using quotes if there are special
+ // characters. Single quotes themselves must be escaped in
+ // either case.
+ const UnicodeString& text = formats[i];
+ int32_t textLength = text.length();
+ int32_t nestingLevel = 0;
+ for (int32_t j = 0; j < textLength; ++j) {
+ UChar c = text[j];
+ if (c == SINGLE_QUOTE && nestingLevel == 0) {
+ // Double each top-level apostrophe.
+ result.append(c);
+ } else if (c == VERTICAL_BAR && nestingLevel == 0) {
+ // Surround each pipe symbol with apostrophes for quoting.
+ // If the next character is an apostrophe, then that will be doubled,
+ // and although the parser will see the apostrophe pairs beginning
+ // and ending one character earlier than our doubling, the result
+ // is as desired.
+ // | -> '|'
+ // |' -> '|'''
+ // |'' -> '|''''' etc.
+ result.append(SINGLE_QUOTE).append(c).append(SINGLE_QUOTE);
+ continue; // Skip the append(c) at the end of the loop body.
+ } else if (c == LEFT_CURLY_BRACE) {
+ ++nestingLevel;
+ } else if (c == RIGHT_CURLY_BRACE && nestingLevel > 0) {
+ --nestingLevel;
+ }
+ result.append(c);
+ }
+ }
+ // Apply the reconstructed pattern.
+ applyPattern(result, errorCode);
+}
+
+// -------------------------------------
+// Gets the limit array.
+
+const double*
+ChoiceFormat::getLimits(int32_t& cnt) const
+{
+ cnt = 0;
+ return NULL;
+}
+
+// -------------------------------------
+// Gets the closures array.
+
+const UBool*
+ChoiceFormat::getClosures(int32_t& cnt) const
+{
+ cnt = 0;
+ return NULL;
+}
+
+// -------------------------------------
+// Gets the format array.
+
+const UnicodeString*
+ChoiceFormat::getFormats(int32_t& cnt) const
+{
+ cnt = 0;
+ return NULL;
+}
+
+// -------------------------------------
+// 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 an int32_t number, it's actually formatted as
+// a double.
+
+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
+{
+ if (msgPattern.countParts() == 0) {
+ // No pattern was applied, or it failed.
+ return appendTo;
+ }
+ // Get the appropriate sub-message.
+ int32_t msgStart = findSubMessage(msgPattern, 0, number);
+ if (!MessageImpl::jdkAposMode(msgPattern)) {
+ int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
+ int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
+ appendTo.append(msgPattern.getPatternString(),
+ patternStart,
+ msgPattern.getPatternIndex(msgLimit) - patternStart);
+ return appendTo;
+ }
+ // JDK compatibility mode: Remove SKIP_SYNTAX.
+ return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
+}
+
+int32_t
+ChoiceFormat::findSubMessage(const MessagePattern &pattern, int32_t partIndex, double number) {
+ int32_t count = pattern.countParts();
+ int32_t msgStart;
+ // Iterate over (ARG_INT|DOUBLE, ARG_SELECTOR, message) tuples
+ // until ARG_LIMIT or end of choice-only pattern.
+ // Ignore the first number and selector and start the loop on the first message.
+ partIndex += 2;
+ for (;;) {
+ // Skip but remember the current sub-message.
+ msgStart = partIndex;
+ partIndex = pattern.getLimitPartIndex(partIndex);
+ if (++partIndex >= count) {
+ // Reached the end of the choice-only pattern.
+ // Return with the last sub-message.
+ break;
+ }
+ const MessagePattern::Part &part = pattern.getPart(partIndex++);
+ UMessagePatternPartType type = part.getType();
+ if (type == UMSGPAT_PART_TYPE_ARG_LIMIT) {
+ // Reached the end of the ChoiceFormat style.
+ // Return with the last sub-message.
+ break;
+ }
+ // part is an ARG_INT or ARG_DOUBLE
+ U_ASSERT(MessagePattern::Part::hasNumericValue(type));
+ double boundary = pattern.getNumericValue(part);
+ // Fetch the ARG_SELECTOR character.
+ int32_t selectorIndex = pattern.getPatternIndex(partIndex++);
+ UChar boundaryChar = pattern.getPatternString().charAt(selectorIndex);
+ if (boundaryChar == LESS_THAN ? !(number > boundary) : !(number >= boundary)) {
+ // The number is in the interval between the previous boundary and the current one.
+ // Return with the sub-message between them.
+ // The !(a>b) and !(a>=b) comparisons are equivalent to
+ // (a<=b) and (a<b) except they "catch" NaN.
+ break;
+ }
+ }
+ return msgStart;
+}
+
+// -------------------------------------
+// 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;
+ }
+ if (msgPattern.countParts() == 0) {
+ status = U_INVALID_STATE_ERROR;
+ return appendTo;
+ }
+
+ for (int32_t i = 0; i < cnt; i++) {
+ double objDouble = objs[i].getDouble(status);
+ if (U_SUCCESS(status)) {
+ format(objDouble, appendTo, 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& pos) const
+{
+ result.setDouble(parseArgument(msgPattern, 0, text, pos));
+}
+
+double
+ChoiceFormat::parseArgument(
+ const MessagePattern &pattern, int32_t partIndex,
+ const UnicodeString &source, ParsePosition &pos) {
+ // find the best number (defined as the one with the longest parse)
+ int32_t start = pos.getIndex();
+ int32_t furthest = start;
+ double bestNumber = uprv_getNaN();
+ double tempNumber = 0.0;
+ int32_t count = pattern.countParts();
+ while (partIndex < count && pattern.getPartType(partIndex) != UMSGPAT_PART_TYPE_ARG_LIMIT) {
+ tempNumber = pattern.getNumericValue(pattern.getPart(partIndex));
+ partIndex += 2; // skip the numeric part and ignore the ARG_SELECTOR
+ int32_t msgLimit = pattern.getLimitPartIndex(partIndex);
+ int32_t len = matchStringUntilLimitPart(pattern, partIndex, msgLimit, source, start);
+ if (len >= 0) {
+ int32_t newIndex = start + len;
+ if (newIndex > furthest) {
+ furthest = newIndex;
+ bestNumber = tempNumber;
+ if (furthest == source.length()) {
+ break;
+ }
+ }
+ }
+ partIndex = msgLimit + 1;
+ }
+ if (furthest == start) {
+ pos.setErrorIndex(start);
+ } else {
+ pos.setIndex(furthest);
+ }
+ return bestNumber;
+}
+
+int32_t
+ChoiceFormat::matchStringUntilLimitPart(
+ const MessagePattern &pattern, int32_t partIndex, int32_t limitPartIndex,
+ const UnicodeString &source, int32_t sourceOffset) {
+ int32_t matchingSourceLength = 0;
+ const UnicodeString &msgString = pattern.getPatternString();
+ int32_t prevIndex = pattern.getPart(partIndex).getLimit();
+ for (;;) {
+ const MessagePattern::Part &part = pattern.getPart(++partIndex);
+ if (partIndex == limitPartIndex || part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
+ int32_t index = part.getIndex();
+ int32_t length = index - prevIndex;
+ if (length != 0 && 0 != source.compare(sourceOffset, length, msgString, prevIndex, length)) {
+ return -1; // mismatch
+ }
+ matchingSourceLength += length;
+ if (partIndex == limitPartIndex) {
+ return matchingSourceLength;
+ }
+ prevIndex = part.getLimit(); // SKIP_SYNTAX
+ }
+ }
+}
+
+// -------------------------------------
+// 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-4.8.1/i18n/coleitr.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/coleitr.cpp
new file mode 100644
index 00000000000..173166af622
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/coleitr.cpp
@@ -0,0 +1,485 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2010, 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 = (int)(m_data_->iteratordata_.endp - m_data_->iteratordata_.string);
+ int thatlength = (int)(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.getBuffer()
+ != that.m_data_->iteratordata_.pos
+ - that.m_data_->iteratordata_.writableBuffer.getBuffer()) {
+ // 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((UChar *)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;
+ }
+ /* Free offsetBuffer before initializing it. */
+ ucol_freeOffsetBuffer(&(m_data_->iteratordata_));
+ uprv_init_collIterate(m_data_->iteratordata_.coll, string, length,
+ &m_data_->iteratordata_, &status);
+
+ 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((UChar *)m_data_->iteratordata_.string);
+ }
+ m_data_->isWritable = TRUE;
+ /* Free offsetBuffer before initializing it. */
+ ucol_freeOffsetBuffer(&(m_data_->iteratordata_));
+ uprv_init_collIterate(m_data_->iteratordata_.coll, buffer, length,
+ &m_data_->iteratordata_, &status);
+ 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 = (int)(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((UChar *)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) {
+ coliter->writableBuffer = othercoliter->writableBuffer;
+ coliter->writableBuffer.getTerminatedBuffer();
+ }
+
+ /* current position */
+ if (othercoliter->pos >= othercoliter->string &&
+ othercoliter->pos <= othercoliter->endp)
+ {
+ coliter->pos = coliter->string +
+ (othercoliter->pos - othercoliter->string);
+ }
+ else {
+ coliter->pos = coliter->writableBuffer.getTerminatedBuffer() +
+ (othercoliter->pos - othercoliter->writableBuffer.getBuffer());
+ }
+
+ /* CE buffer */
+ int32_t CEsize;
+ if (coliter->extendCEs) {
+ uprv_memcpy(coliter->CEs, othercoliter->CEs, sizeof(uint32_t) * UCOL_EXPAND_CE_BUFFER_SIZE);
+ CEsize = sizeof(othercoliter->extendCEs);
+ if (CEsize > 0) {
+ othercoliter->extendCEs = (uint32_t *)uprv_malloc(CEsize);
+ uprv_memcpy(coliter->extendCEs, othercoliter->extendCEs, CEsize);
+ }
+ coliter->toReturn = coliter->extendCEs +
+ (othercoliter->toReturn - othercoliter->extendCEs);
+ coliter->CEpos = coliter->extendCEs + CEsize;
+ } else {
+ 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-4.8.1/i18n/coll.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/coll.cpp
new file mode 100644
index 00000000000..f044e292b99
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/coll.cpp
@@ -0,0 +1,880 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2011, 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 "uresimp.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("");
+
+ LocaleUtility::initLocaleFromName(*actualReturn, currentLocale);
+ result->setLocales(lkey.canonicalLocale(canonicalLocale), currentLocale, 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);
+ RuleBasedCollator *rbc;
+ if (col && (rbc = dynamic_cast<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)
+ {
+ availableLocaleListCount = localeCount;
+ availableLocaleList = temp;
+ 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, 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 is 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);
+}
+
+UCollationResult Collator::compare(UCharIterator &/*sIter*/,
+ UCharIterator &/*tIter*/,
+ UErrorCode &status) const {
+ if(U_SUCCESS(status)) {
+ // Not implemented in the base class.
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return UCOL_EQUAL;
+}
+
+UCollationResult Collator::compareUTF8(const StringPiece &source,
+ const StringPiece &target,
+ UErrorCode &status) const {
+ if(U_FAILURE(status)) {
+ return UCOL_EQUAL;
+ }
+ UCharIterator sIter, tIter;
+ uiter_setUTF8(&sIter, source.data(), source.length());
+ uiter_setUTF8(&tIter, target.data(), target.length());
+ return compare(sIter, tIter, status);
+}
+
+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 */, const Locale& /*actualLocale*/) {
+}
+
+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();
+ if (result) {
+ 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 = (int32_t)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);
+}
+
+StringEnumeration* U_EXPORT2
+Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
+ UBool commonlyUsed, UErrorCode& status) {
+ // This is a wrapper over ucol_getKeywordValuesForLocale
+ UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(),
+ commonlyUsed, &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);
+}
+
+int32_t U_EXPORT2
+Collator::getReorderCodes(int32_t* /* dest*/,
+ int32_t /* destCapacity*/,
+ UErrorCode& status) const
+{
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return 0;
+}
+
+void U_EXPORT2
+Collator::setReorderCodes(const int32_t* /* reorderCodes */,
+ int32_t /* reorderCodesLength */,
+ UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+}
+
+int32_t U_EXPORT2
+Collator::getEquivalentReorderCodes(int32_t /* reorderCode */,
+ int32_t* /* dest */,
+ int32_t /* destCapacity */,
+ UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return 0;
+}
+
+// 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-4.8.1/i18n/colldata.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/colldata.cpp
new file mode 100644
index 00000000000..6d73aeacc40
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/colldata.cpp
@@ -0,0 +1,1102 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2011, International Business Machines *
+ * Corporation and others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/unistr.h"
+#include "unicode/putil.h"
+#include "unicode/usearch.h"
+
+#include "cmemory.h"
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/ucoleitr.h"
+
+#include "unicode/regex.h" // TODO: make conditional on regexp being built.
+
+#include "unicode/uniset.h"
+#include "unicode/uset.h"
+#include "unicode/ustring.h"
+#include "hash.h"
+#include "uhash.h"
+#include "ucln_in.h"
+#include "ucol_imp.h"
+#include "umutex.h"
+
+#include "unicode/colldata.h"
+
+U_NAMESPACE_BEGIN
+
+#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 ARRAY_COPY(dst, src, count) uprv_memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0])
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CEList)
+
+#ifdef INSTRUMENT_CELIST
+int32_t CEList::_active = 0;
+int32_t CEList::_histogram[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+
+CEList::CEList(UCollator *coll, const UnicodeString &string, UErrorCode &status)
+ : ces(NULL), listMax(CELIST_BUFFER_SIZE), listSize(0)
+{
+ UCollationElements *elems = ucol_openElements(coll, string.getBuffer(), string.length(), &status);
+ UCollationStrength strength = ucol_getStrength(coll);
+ UBool toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, &status) == UCOL_SHIFTED;
+ uint32_t variableTop = ucol_getVariableTop(coll, &status);
+ uint32_t strengthMask = 0;
+ int32_t order;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // **** only set flag if string has Han(gul) ****
+ ucol_forceHanImplicit(elems, &status);
+
+ switch (strength)
+ {
+ default:
+ strengthMask |= UCOL_TERTIARYORDERMASK;
+ /* fall through */
+
+ case UCOL_SECONDARY:
+ strengthMask |= UCOL_SECONDARYORDERMASK;
+ /* fall through */
+
+ case UCOL_PRIMARY:
+ strengthMask |= UCOL_PRIMARYORDERMASK;
+ }
+
+#ifdef INSTRUMENT_CELIST
+ _active += 1;
+ _histogram[0] += 1;
+#endif
+
+ ces = ceBuffer;
+
+ while ((order = ucol_next(elems, &status)) != UCOL_NULLORDER) {
+ UBool cont = isContinuation(order);
+
+ order &= strengthMask;
+
+ if (toShift && variableTop > (uint32_t)order && (order & UCOL_PRIMARYORDERMASK) != 0) {
+ if (strength >= UCOL_QUATERNARY) {
+ order &= UCOL_PRIMARYORDERMASK;
+ } else {
+ order = UCOL_IGNORABLE;
+ }
+ }
+
+ if (order == UCOL_IGNORABLE) {
+ continue;
+ }
+
+ if (cont) {
+ order |= UCOL_CONTINUATION_MARKER;
+ }
+
+ add(order, status);
+ }
+
+ ucol_closeElements(elems);
+}
+
+CEList::~CEList()
+{
+#ifdef INSTRUMENT_CELIST
+ _active -= 1;
+#endif
+
+ if (ces != ceBuffer) {
+ DELETE_ARRAY(ces);
+ }
+}
+
+void CEList::add(uint32_t ce, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (listSize >= listMax) {
+ int32_t newMax = listMax + CELIST_BUFFER_SIZE;
+
+#ifdef INSTRUMENT_CELIST
+ _histogram[listSize / CELIST_BUFFER_SIZE] += 1;
+#endif
+
+ uint32_t *newCEs = NEW_ARRAY(uint32_t, newMax);
+
+ if (newCEs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ uprv_memcpy(newCEs, ces, listSize * sizeof(uint32_t));
+
+ if (ces != ceBuffer) {
+ DELETE_ARRAY(ces);
+ }
+
+ ces = newCEs;
+ listMax = newMax;
+ }
+
+ ces[listSize++] = ce;
+}
+
+uint32_t CEList::get(int32_t index) const
+{
+ if (index >= 0 && index < listSize) {
+ return ces[index];
+ }
+
+ return UCOL_NULLORDER;
+}
+
+uint32_t &CEList::operator[](int32_t index) const
+{
+ return ces[index];
+}
+
+UBool CEList::matchesAt(int32_t offset, const CEList *other) const
+{
+ if (other == NULL || listSize - offset < other->size()) {
+ return FALSE;
+ }
+
+ for (int32_t i = offset, j = 0; j < other->size(); i += 1, j += 1) {
+ if (ces[i] != (*other)[j]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+int32_t CEList::size() const
+{
+ return listSize;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringList)
+
+#ifdef INSTRUMENT_STRING_LIST
+int32_t StringList::_lists = 0;
+int32_t StringList::_strings = 0;
+int32_t StringList::_histogram[101] = {0};
+#endif
+
+StringList::StringList(UErrorCode &status)
+ : strings(NULL), listMax(STRING_LIST_BUFFER_SIZE), listSize(0)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ strings = new UnicodeString [listMax];
+
+ if (strings == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+#ifdef INSTRUMENT_STRING_LIST
+ _lists += 1;
+ _histogram[0] += 1;
+#endif
+}
+
+StringList::~StringList()
+{
+ delete[] strings;
+}
+
+void StringList::add(const UnicodeString *string, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+#ifdef INSTRUMENT_STRING_LIST
+ _strings += 1;
+#endif
+
+ if (listSize >= listMax) {
+ int32_t newMax = listMax + STRING_LIST_BUFFER_SIZE;
+ UnicodeString *newStrings = new UnicodeString[newMax];
+ if (newStrings == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (int32_t i=0; i<listSize; ++i) {
+ newStrings[i] = strings[i];
+ }
+
+#ifdef INSTRUMENT_STRING_LIST
+ int32_t _h = listSize / STRING_LIST_BUFFER_SIZE;
+
+ if (_h > 100) {
+ _h = 100;
+ }
+
+ _histogram[_h] += 1;
+#endif
+
+ delete[] strings;
+ strings = newStrings;
+ listMax = newMax;
+ }
+
+ // The ctor initialized all the strings in
+ // the array to empty strings, so this
+ // is the same as copying the source string.
+ strings[listSize++].append(*string);
+}
+
+void StringList::add(const UChar *chars, int32_t count, UErrorCode &status)
+{
+ const UnicodeString string(chars, count);
+
+ add(&string, status);
+}
+
+const UnicodeString *StringList::get(int32_t index) const
+{
+ if (index >= 0 && index < listSize) {
+ return &strings[index];
+ }
+
+ return NULL;
+}
+
+int32_t StringList::size() const
+{
+ return listSize;
+}
+
+
+U_CFUNC void deleteStringList(void *obj);
+
+class CEToStringsMap : public UMemory
+{
+public:
+
+ CEToStringsMap(UErrorCode &status);
+ ~CEToStringsMap();
+
+ void put(uint32_t ce, UnicodeString *string, UErrorCode &status);
+ StringList *getStringList(uint32_t ce) const;
+
+private:
+
+ void putStringList(uint32_t ce, StringList *stringList, UErrorCode &status);
+ UHashtable *map;
+};
+
+CEToStringsMap::CEToStringsMap(UErrorCode &status)
+ : map(NULL)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ map = uhash_open(uhash_hashLong, uhash_compareLong,
+ uhash_compareCaselessUnicodeString,
+ &status);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ uhash_setValueDeleter(map, deleteStringList);
+}
+
+CEToStringsMap::~CEToStringsMap()
+{
+ uhash_close(map);
+}
+
+void CEToStringsMap::put(uint32_t ce, UnicodeString *string, UErrorCode &status)
+{
+ StringList *strings = getStringList(ce);
+
+ if (strings == NULL) {
+ strings = new StringList(status);
+
+ if (strings == NULL || U_FAILURE(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ putStringList(ce, strings, status);
+ }
+
+ strings->add(string, status);
+}
+
+StringList *CEToStringsMap::getStringList(uint32_t ce) const
+{
+ return (StringList *) uhash_iget(map, ce);
+}
+
+void CEToStringsMap::putStringList(uint32_t ce, StringList *stringList, UErrorCode &status)
+{
+ uhash_iput(map, ce, (void *) stringList, &status);
+}
+
+U_CFUNC void deleteStringList(void *obj)
+{
+ StringList *strings = (StringList *) obj;
+
+ delete strings;
+}
+
+U_CFUNC void deleteCEList(void *obj);
+U_CFUNC void deleteUnicodeStringKey(void *obj);
+
+class StringToCEsMap : public UMemory
+{
+public:
+ StringToCEsMap(UErrorCode &status);
+ ~StringToCEsMap();
+
+ void put(const UnicodeString *string, const CEList *ces, UErrorCode &status);
+ const CEList *get(const UnicodeString *string);
+ void free(const CEList *list);
+
+private:
+
+
+ UHashtable *map;
+};
+
+StringToCEsMap::StringToCEsMap(UErrorCode &status)
+ : map(NULL)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ map = uhash_open(uhash_hashUnicodeString,
+ uhash_compareUnicodeString,
+ uhash_compareLong,
+ &status);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ uhash_setValueDeleter(map, deleteCEList);
+ uhash_setKeyDeleter(map, deleteUnicodeStringKey);
+}
+
+StringToCEsMap::~StringToCEsMap()
+{
+ uhash_close(map);
+}
+
+void StringToCEsMap::put(const UnicodeString *string, const CEList *ces, UErrorCode &status)
+{
+ uhash_put(map, (void *) string, (void *) ces, &status);
+}
+
+const CEList *StringToCEsMap::get(const UnicodeString *string)
+{
+ return (const CEList *) uhash_get(map, string);
+}
+
+U_CFUNC void deleteCEList(void *obj)
+{
+ CEList *list = (CEList *) obj;
+
+ delete list;
+}
+
+U_CFUNC void deleteUnicodeStringKey(void *obj)
+{
+ UnicodeString *key = (UnicodeString *) obj;
+
+ delete key;
+}
+
+class CollDataCacheEntry : public UMemory
+{
+public:
+ CollDataCacheEntry(CollData *theData);
+ ~CollDataCacheEntry();
+
+ CollData *data;
+ int32_t refCount;
+};
+
+CollDataCacheEntry::CollDataCacheEntry(CollData *theData)
+ : data(theData), refCount(1)
+{
+ // nothing else to do
+}
+
+CollDataCacheEntry::~CollDataCacheEntry()
+{
+ // check refCount?
+ delete data;
+}
+
+class CollDataCache : public UMemory
+{
+public:
+ CollDataCache(UErrorCode &status);
+ ~CollDataCache();
+
+ CollData *get(UCollator *collator, UErrorCode &status);
+ void unref(CollData *collData);
+
+ void flush();
+
+private:
+ static char *getKey(UCollator *collator, char *keyBuffer, int32_t *charBufferLength);
+ static void deleteKey(char *key);
+
+ UHashtable *cache;
+};
+static UMTX lock;
+
+U_CFUNC void deleteChars(void * /*obj*/)
+{
+ // char *chars = (char *) obj;
+ // All the key strings are owned by the
+ // CollData objects and don't need to
+ // be freed here.
+ //DELETE_ARRAY(chars);
+}
+
+U_CFUNC void deleteCollDataCacheEntry(void *obj)
+{
+ CollDataCacheEntry *entry = (CollDataCacheEntry *) obj;
+
+ delete entry;
+}
+
+CollDataCache::CollDataCache(UErrorCode &status)
+ : cache(NULL)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ cache = uhash_open(uhash_hashChars, uhash_compareChars, uhash_compareLong, &status);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ uhash_setValueDeleter(cache, deleteCollDataCacheEntry);
+ uhash_setKeyDeleter(cache, deleteChars);
+}
+
+CollDataCache::~CollDataCache()
+{
+ umtx_lock(&lock);
+ uhash_close(cache);
+ cache = NULL;
+ umtx_unlock(&lock);
+}
+
+CollData *CollDataCache::get(UCollator *collator, UErrorCode &status)
+{
+ char keyBuffer[KEY_BUFFER_SIZE];
+ int32_t keyLength = KEY_BUFFER_SIZE;
+ char *key = getKey(collator, keyBuffer, &keyLength);
+ CollData *result = NULL, *newData = NULL;
+ CollDataCacheEntry *entry = NULL, *newEntry = NULL;
+
+ umtx_lock(&lock);
+ entry = (CollDataCacheEntry *) uhash_get(cache, key);
+
+ if (entry == NULL) {
+ umtx_unlock(&lock);
+
+ newData = new CollData(collator, key, keyLength, status);
+ newEntry = new CollDataCacheEntry(newData);
+
+ if (U_FAILURE(status) || newData == NULL || newEntry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ umtx_lock(&lock);
+ entry = (CollDataCacheEntry *) uhash_get(cache, key);
+
+ if (entry == NULL) {
+ uhash_put(cache, newData->key, newEntry, &status);
+ umtx_unlock(&lock);
+
+ if (U_FAILURE(status)) {
+ delete newEntry;
+ delete newData;
+
+ return NULL;
+ }
+
+ return newData;
+ }
+ }
+
+ result = entry->data;
+ entry->refCount += 1;
+ umtx_unlock(&lock);
+
+ if (key != keyBuffer) {
+ deleteKey(key);
+ }
+
+ if (newEntry != NULL) {
+ delete newEntry;
+ delete newData;
+ }
+
+ return result;
+}
+
+void CollDataCache::unref(CollData *collData)
+{
+ CollDataCacheEntry *entry = NULL;
+
+ umtx_lock(&lock);
+ entry = (CollDataCacheEntry *) uhash_get(cache, collData->key);
+
+ if (entry != NULL) {
+ entry->refCount -= 1;
+ }
+ umtx_unlock(&lock);
+}
+
+char *CollDataCache::getKey(UCollator *collator, char *keyBuffer, int32_t *keyBufferLength)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = ucol_getShortDefinitionString(collator, NULL, keyBuffer, *keyBufferLength, &status);
+
+ if (len >= *keyBufferLength) {
+ *keyBufferLength = (len + 2) & ~1; // round to even length, leaving room for terminating null
+ keyBuffer = NEW_ARRAY(char, *keyBufferLength);
+ status = U_ZERO_ERROR;
+
+ len = ucol_getShortDefinitionString(collator, NULL, keyBuffer, *keyBufferLength, &status);
+ }
+
+ keyBuffer[len] = '\0';
+
+ return keyBuffer;
+}
+
+void CollDataCache::flush()
+{
+ const UHashElement *element;
+ int32_t pos = -1;
+
+ umtx_lock(&lock);
+ while ((element = uhash_nextElement(cache, &pos)) != NULL) {
+ CollDataCacheEntry *entry = (CollDataCacheEntry *) element->value.pointer;
+
+ if (entry->refCount <= 0) {
+ uhash_removeElement(cache, element);
+ }
+ }
+ umtx_unlock(&lock);
+}
+
+void CollDataCache::deleteKey(char *key)
+{
+ DELETE_ARRAY(key);
+}
+
+U_CDECL_BEGIN
+static UBool coll_data_cleanup(void) {
+ CollData::freeCollDataCache();
+ return TRUE;
+}
+U_CDECL_END
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollData)
+
+CollData::CollData()
+{
+ // nothing
+}
+
+#define CLONE_COLLATOR
+
+//#define CACHE_CELISTS
+CollData::CollData(UCollator *collator, char *cacheKey, int32_t cacheKeyLength, UErrorCode &status)
+ : coll(NULL), charsToCEList(NULL), ceToCharsStartingWith(NULL), key(NULL)
+{
+ // [:c:] == [[:cn:][:cc:][:co:][:cf:][:cs:]]
+ // i.e. other, control, private use, format, surrogate
+ U_STRING_DECL(test_pattern, "[[:assigned:]-[:c:]]", 20);
+ U_STRING_INIT(test_pattern, "[[:assigned:]-[:c:]]", 20);
+ USet *charsToTest = uset_openPattern(test_pattern, 20, &status);
+
+ // Han ext. A, Han, Jamo, Hangul, Han Ext. B
+ // i.e. all the characers we handle implicitly
+ U_STRING_DECL(remove_pattern, "[[\\u3400-\\u9FFF][\\u1100-\\u11F9][\\uAC00-\\uD7AF][\\U00020000-\\U0002A6DF]]", 70);
+ U_STRING_INIT(remove_pattern, "[[\\u3400-\\u9FFF][\\u1100-\\u11F9][\\uAC00-\\uD7AF][\\U00020000-\\U0002A6DF]]", 70);
+ USet *charsToRemove = uset_openPattern(remove_pattern, 70, &status);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ USet *expansions = uset_openEmpty();
+ USet *contractions = uset_openEmpty();
+ int32_t itemCount;
+
+#ifdef CACHE_CELISTS
+ charsToCEList = new StringToCEsMap(status);
+
+ if (U_FAILURE(status)) {
+ goto bail;
+ }
+#else
+ charsToCEList = NULL;
+#endif
+
+ ceToCharsStartingWith = new CEToStringsMap(status);
+
+ if (U_FAILURE(status)) {
+ goto bail;
+ }
+
+ if (cacheKeyLength > KEY_BUFFER_SIZE) {
+ key = NEW_ARRAY(char, cacheKeyLength);
+
+ if (key == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto bail;
+ }
+ } else {
+ key = keyBuffer;
+ }
+
+ ARRAY_COPY(key, cacheKey, cacheKeyLength);
+
+#ifdef CLONE_COLLATOR
+ coll = ucol_safeClone(collator, NULL, NULL, &status);
+
+ if (U_FAILURE(status)) {
+ goto bail;
+ }
+#else
+ coll = collator;
+#endif
+
+ ucol_getContractionsAndExpansions(coll, contractions, expansions, FALSE, &status);
+
+ uset_addAll(charsToTest, contractions);
+ uset_addAll(charsToTest, expansions);
+ uset_removeAll(charsToTest, charsToRemove);
+
+ itemCount = uset_getItemCount(charsToTest);
+ for(int32_t item = 0; item < itemCount; item += 1) {
+ UChar32 start = 0, end = 0;
+ UChar buffer[16];
+ int32_t len = uset_getItem(charsToTest, item, &start, &end,
+ buffer, 16, &status);
+
+ if (len == 0) {
+ for (UChar32 ch = start; ch <= end; ch += 1) {
+ UnicodeString *st = new UnicodeString(ch);
+
+ if (st == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+ CEList *ceList = new CEList(coll, *st, status);
+
+ ceToCharsStartingWith->put(ceList->get(0), st, status);
+
+#ifdef CACHE_CELISTS
+ charsToCEList->put(st, ceList, status);
+#else
+ delete ceList;
+ delete st;
+#endif
+ }
+ } else if (len > 0) {
+ UnicodeString *st = new UnicodeString(buffer, len);
+
+ if (st == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+ CEList *ceList = new CEList(coll, *st, status);
+
+ ceToCharsStartingWith->put(ceList->get(0), st, status);
+
+#ifdef CACHE_CELISTS
+ charsToCEList->put(st, ceList, status);
+#else
+ delete ceList;
+ delete st;
+#endif
+ } else {
+ // shouldn't happen...
+ }
+
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+
+bail:
+ uset_close(contractions);
+ uset_close(expansions);
+ uset_close(charsToRemove);
+ uset_close(charsToTest);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UChar32 hanRanges[] = {UCOL_FIRST_HAN, UCOL_LAST_HAN, UCOL_FIRST_HAN_COMPAT, UCOL_LAST_HAN_COMPAT, UCOL_FIRST_HAN_A, UCOL_LAST_HAN_A,
+ UCOL_FIRST_HAN_B, UCOL_LAST_HAN_B};
+ UChar jamoRanges[] = {UCOL_FIRST_L_JAMO, UCOL_FIRST_V_JAMO, UCOL_FIRST_T_JAMO, UCOL_LAST_T_JAMO};
+ UnicodeString hanString = UnicodeString::fromUTF32(hanRanges, ARRAY_SIZE(hanRanges));
+ UnicodeString jamoString(FALSE, jamoRanges, ARRAY_SIZE(jamoRanges));
+ CEList hanList(coll, hanString, status);
+ CEList jamoList(coll, jamoString, status);
+ int32_t j = 0;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ for (int32_t c = 0; c < jamoList.size(); c += 1) {
+ uint32_t jce = jamoList[c];
+
+ if (! isContinuation(jce)) {
+ jamoLimits[j++] = jce;
+ }
+ }
+
+ jamoLimits[3] += (1 << UCOL_PRIMARYORDERSHIFT);
+
+ minHan = 0xFFFFFFFF;
+ maxHan = 0;
+
+ for(int32_t h = 0; h < hanList.size(); h += 2) {
+ uint32_t han = (uint32_t) hanList[h];
+
+ if (han < minHan) {
+ minHan = han;
+ }
+
+ if (han > maxHan) {
+ maxHan = han;
+ }
+ }
+
+ maxHan += (1 << UCOL_PRIMARYORDERSHIFT);
+}
+
+CollData::~CollData()
+{
+#ifdef CLONE_COLLATOR
+ ucol_close(coll);
+#endif
+
+ if (key != keyBuffer) {
+ DELETE_ARRAY(key);
+ }
+
+ delete ceToCharsStartingWith;
+
+#ifdef CACHE_CELISTS
+ delete charsToCEList;
+#endif
+}
+
+UCollator *CollData::getCollator() const
+{
+ return coll;
+}
+
+const StringList *CollData::getStringList(int32_t ce) const
+{
+ return ceToCharsStartingWith->getStringList(ce);
+}
+
+const CEList *CollData::getCEList(const UnicodeString *string) const
+{
+#ifdef CACHE_CELISTS
+ return charsToCEList->get(string);
+#else
+ UErrorCode status = U_ZERO_ERROR;
+ const CEList *list = new CEList(coll, *string, status);
+
+ if (U_FAILURE(status)) {
+ delete list;
+ list = NULL;
+ }
+
+ return list;
+#endif
+}
+
+void CollData::freeCEList(const CEList *list)
+{
+#ifndef CACHE_CELISTS
+ delete list;
+#endif
+}
+
+int32_t CollData::minLengthInChars(const CEList *ceList, int32_t offset, int32_t *history) const
+{
+ // find out shortest string for the longest sequence of ces.
+ // this can probably be folded with the minLengthCache...
+
+ if (history[offset] >= 0) {
+ return history[offset];
+ }
+
+ uint32_t ce = ceList->get(offset);
+ int32_t maxOffset = ceList->size();
+ int32_t shortestLength = INT32_MAX;
+ const StringList *strings = ceToCharsStartingWith->getStringList(ce);
+
+ if (strings != NULL) {
+ int32_t stringCount = strings->size();
+
+ for (int32_t s = 0; s < stringCount; s += 1) {
+ const UnicodeString *string = strings->get(s);
+#ifdef CACHE_CELISTS
+ const CEList *ceList2 = charsToCEList->get(string);
+#else
+ UErrorCode status = U_ZERO_ERROR;
+ const CEList *ceList2 = new CEList(coll, *string, status);
+
+ if (U_FAILURE(status)) {
+ delete ceList2;
+ ceList2 = NULL;
+ }
+#endif
+
+ if (ceList->matchesAt(offset, ceList2)) {
+ int32_t clength = ceList2->size();
+ int32_t slength = string->length();
+ int32_t roffset = offset + clength;
+ int32_t rlength = 0;
+
+ if (roffset < maxOffset) {
+ rlength = minLengthInChars(ceList, roffset, history);
+
+ if (rlength <= 0) {
+ // delete before continue to avoid memory leak.
+#ifndef CACHE_CELISTS
+ delete ceList2;
+#endif
+ // ignore any dead ends
+ continue;
+ }
+ }
+
+ if (shortestLength > slength + rlength) {
+ shortestLength = slength + rlength;
+ }
+ }
+
+#ifndef CACHE_CELISTS
+ delete ceList2;
+#endif
+ }
+ }
+
+ if (shortestLength == INT32_MAX) {
+ // No matching strings at this offset. See if
+ // the CE is in a range we can handle manually.
+ if (ce >= minHan && ce < maxHan) {
+ // all han have implicit orders which
+ // generate two CEs.
+ int32_t roffset = offset + 2;
+ int32_t rlength = 0;
+
+ //history[roffset++] = -1;
+ //history[roffset++] = 1;
+
+ if (roffset < maxOffset) {
+ rlength = minLengthInChars(ceList, roffset, history);
+ }
+
+ if (rlength < 0) {
+ return -1;
+ }
+
+ shortestLength = 1 + rlength;
+ goto have_shortest;
+ } else if (ce >= jamoLimits[0] && ce < jamoLimits[3]) {
+ int32_t roffset = offset;
+ int32_t rlength = 0;
+
+ // **** this loop may not handle archaic Hangul correctly ****
+ for (int32_t j = 0; roffset < maxOffset && j < 4; j += 1, roffset += 1) {
+ uint32_t jce = ceList->get(roffset);
+
+ // Some Jamo have 24-bit primary order; skip the
+ // 2nd CE. This should always be OK because if
+ // we're still in the loop all we've seen are
+ // a series of Jamo in LVT order.
+ if (isContinuation(jce)) {
+ continue;
+ }
+
+ if (j >= 3 || jce < jamoLimits[j] || jce >= jamoLimits[j + 1]) {
+ break;
+ }
+ }
+
+ if (roffset == offset) {
+ // we started with a non-L Jamo...
+ // just say it comes from a single character
+ roffset += 1;
+
+ // See if the single Jamo has a 24-bit order.
+ if (roffset < maxOffset && isContinuation(ceList->get(roffset))) {
+ roffset += 1;
+ }
+ }
+
+ if (roffset < maxOffset) {
+ rlength = minLengthInChars(ceList, roffset, history);
+ }
+
+ if (rlength < 0) {
+ return -1;
+ }
+
+ shortestLength = 1 + rlength;
+ goto have_shortest;
+ }
+
+ // Can't handle it manually either. Just move on.
+ return -1;
+ }
+
+have_shortest:
+ history[offset] = shortestLength;
+
+ return shortestLength;
+}
+
+int32_t CollData::minLengthInChars(const CEList *ceList, int32_t offset) const
+{
+ int32_t clength = ceList->size();
+ int32_t *history = NEW_ARRAY(int32_t, clength);
+
+ for (int32_t i = 0; i < clength; i += 1) {
+ history[i] = -1;
+ }
+
+ int32_t minLength = minLengthInChars(ceList, offset, history);
+
+ DELETE_ARRAY(history);
+
+ return minLength;
+}
+
+CollData *CollData::open(UCollator *collator, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ CollDataCache *cache = getCollDataCache();
+
+ return cache->get(collator, status);
+}
+
+void CollData::close(CollData *collData)
+{
+ CollDataCache *cache = getCollDataCache();
+
+ cache->unref(collData);
+}
+
+CollDataCache *CollData::collDataCache = NULL;
+
+CollDataCache *CollData::getCollDataCache()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ CollDataCache *cache = NULL;
+
+ UMTX_CHECK(NULL, collDataCache, cache);
+
+ if (cache == NULL) {
+ cache = new CollDataCache(status);
+
+ if (U_FAILURE(status)) {
+ delete cache;
+ return NULL;
+ }
+
+ umtx_lock(NULL);
+ if (collDataCache == NULL) {
+ collDataCache = cache;
+
+ ucln_i18n_registerCleanup(UCLN_I18N_COLL_DATA, coll_data_cleanup);
+ }
+ umtx_unlock(NULL);
+
+ if (collDataCache != cache) {
+ delete cache;
+ }
+ }
+
+ return collDataCache;
+}
+
+void CollData::freeCollDataCache()
+{
+ CollDataCache *cache = NULL;
+
+ UMTX_CHECK(NULL, collDataCache, cache);
+
+ if (cache != NULL) {
+ umtx_lock(NULL);
+ if (collDataCache != NULL) {
+ collDataCache = NULL;
+ } else {
+ cache = NULL;
+ }
+ umtx_unlock(NULL);
+
+ delete cache;
+ }
+}
+
+void CollData::flushCollDataCache()
+{
+ CollDataCache *cache = NULL;
+
+ UMTX_CHECK(NULL, collDataCache, cache);
+
+ // **** this will fail if the another ****
+ // **** thread deletes the cache here ****
+ if (cache != NULL) {
+ cache->flush();
+ }
+}
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_COLLATION
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/coptccal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/coptccal.cpp
new file mode 100644
index 00000000000..84bbad797ea
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/coptccal.cpp
@@ -0,0 +1,178 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003 - 2009, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "umutex.h"
+#include "coptccal.h"
+#include "cecal.h"
+#include <float.h>
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CopticCalendar)
+
+static const int32_t COPTIC_JD_EPOCH_OFFSET = 1824665;
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+CopticCalendar::CopticCalendar(const Locale& aLocale, UErrorCode& success)
+: CECalendar(aLocale, success)
+{
+}
+
+CopticCalendar::CopticCalendar (const CopticCalendar& other)
+: CECalendar(other)
+{
+}
+
+CopticCalendar::~CopticCalendar()
+{
+}
+
+Calendar*
+CopticCalendar::clone() const
+{
+ return new CopticCalendar(*this);
+}
+
+const char*
+CopticCalendar::getType() const
+{
+ return "coptic";
+}
+
+//-------------------------------------------------------------------------
+// Calendar framework
+//-------------------------------------------------------------------------
+
+int32_t
+CopticCalendar::handleGetExtendedYear()
+{
+ int32_t eyear;
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else {
+ // The year defaults to the epoch start, the era to CE
+ int32_t era = internalGet(UCAL_ERA, CE);
+ if (era == BCE) {
+ eyear = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
+ } else {
+ eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
+ }
+ }
+ return eyear;
+}
+
+void
+CopticCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
+{
+ int32_t eyear, month, day, era, year;
+ jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
+
+ if (eyear <= 0) {
+ era = BCE;
+ year = 1 - eyear;
+ } else {
+ era = CE;
+ year = eyear;
+ }
+
+ internalSet(UCAL_EXTENDED_YEAR, eyear);
+ internalSet(UCAL_ERA, era);
+ internalSet(UCAL_YEAR, year);
+ internalSet(UCAL_MONTH, month);
+ internalSet(UCAL_DATE, day);
+ internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
+}
+
+const UDate CopticCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t CopticCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate CopticCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t CopticCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+UDate
+CopticCalendar::defaultCenturyStart() const
+{
+ initializeSystemDefaultCentury();
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+CopticCalendar::defaultCenturyStartYear() const
+{
+ initializeSystemDefaultCentury();
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+CopticCalendar::initializeSystemDefaultCentury()
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (!needsUpdate) {
+ return;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ CopticCalendar calendar(Locale("@calendar=coptic"), 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);
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ umtx_unlock(NULL);
+ }
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+}
+
+int32_t
+CopticCalendar::getJDEpochOffset() const
+{
+ return COPTIC_JD_EPOCH_OFFSET;
+}
+
+
+#if 0
+// We do not want to introduce this API in ICU4C.
+// It was accidentally introduced in ICU4J as a public API.
+
+//-------------------------------------------------------------------------
+// Calendar system Conversion methods...
+//-------------------------------------------------------------------------
+
+int32_t
+CopticCalendar::copticToJD(int32_t year, int32_t month, int32_t day)
+{
+ return CECalendar::ceToJD(year, month, day, COPTIC_JD_EPOCH_OFFSET);
+}
+#endif
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/coptccal.h b/Build/source/libs/icu/icu-4.8.1/i18n/coptccal.h
new file mode 100644
index 00000000000..f42230dff4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/coptccal.h
@@ -0,0 +1,272 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef COPTCCAL_H
+#define COPTCCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "cecal.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Implement the Coptic calendar system.
+ * @internal
+ */
+class CopticCalendar : public CECalendar {
+
+public:
+ /**
+ * Useful constants for CopticCalendar.
+ * @internal
+ */
+ enum EMonths {
+ /**
+ * Constant for &#x03c9;&#x03bf;&#x03b3;&#x03c4;/&#x062a;&#xfeee;&#xfe97;,
+ * the 1st month of the Coptic year.
+ */
+ TOUT,
+
+ /**
+ * Constant for &#x03a0;&#x03b1;&#x03bf;&#x03c0;&#x03b9;/&#xfeea;&#xfe91;&#xfe8e;&#xfe91;,
+ * the 2nd month of the Coptic year.
+ */
+ BABA,
+
+ /**
+ * Constant for &#x0391;&#x03b8;&#x03bf;&#x03c1;/&#x0631;&#xfeee;&#xfe97;&#xfe8e;&#xfeeb;,
+ * the 3rd month of the Coptic year.
+ */
+ HATOR,
+
+ /**
+ * Constant for &#x03a7;&#x03bf;&#x03b9;&#x03b1;&#x03ba;/&#xfeda;&#xfeec;&#xfef4;&#xfedb;,
+ * the 4th month of the Coptic year.
+ */
+ KIAHK,
+
+ /**
+ * Constant for &#x03a4;&#x03c9;&#x03b2;&#x03b9;/&#x0637;&#xfeee;&#xfe92;&#xfeeb;,
+ * the 5th month of the Coptic year.
+ */
+ TOBA,
+
+ /**
+ * Constant for &#x039c;&#x03b5;&#x03e3;&#x03b9;&#x03c1;/&#xfeae;&#xfef4;&#xfeb8;&#xfee3;&#x0623;,
+ * the 6th month of the Coptic year.
+ */
+ AMSHIR,
+
+ /**
+ * Constant for &#x03a0;&#x03b1;&#x03c1;&#x03b5;&#x03bc;&#x03e9;&#x03b1;&#x03c4;/&#x062a;&#xfe8e;&#xfeec;&#xfee3;&#xfeae;&#xfe91;,
+ * the 7th month of the Coptic year.
+ */
+ BARAMHAT,
+
+ /**
+ * Constant for &#x03a6;&#x03b1;&#x03c1;&#x03bc;&#x03bf;&#x03b8;&#x03b9;/&#x0647;&#x062f;&#xfeee;&#xfee3;&#xfeae;&#xfe91;,
+ * the 8th month of the Coptic year.
+ */
+ BARAMOUDA,
+
+ /**
+ * Constant for &#x03a0;&#x03b1;&#x03e3;&#x03b1;&#x03bd;/&#xfeb2;&#xfee8;&#xfeb8;&#xfe91;,
+ * the 9th month of the Coptic year.
+ */
+ BASHANS,
+
+ /**
+ * Constant for &#x03a0;&#x03b1;&#x03c9;&#x03bd;&#x03b9;/&#xfeea;&#xfee7;&#x0624;&#xfeee;&#xfe91;,
+ * the 10th month of the Coptic year.
+ */
+ PAONA,
+
+ /**
+ * Constant for &#x0395;&#x03c0;&#x03b7;&#x03c0;/&#xfe90;&#xfef4;&#xfe91;&#x0623;,
+ * the 11th month of the Coptic year.
+ */
+ EPEP,
+
+ /**
+ * Constant for &#x039c;&#x03b5;&#x03f2;&#x03c9;&#x03c1;&#x03b7;/&#x0649;&#xfeae;&#xfeb4;&#xfee3;,
+ * the 12th month of the Coptic year.
+ */
+ MESRA,
+
+ /**
+ * Constant for &#x03a0;&#x03b9;&#x03ba;&#x03bf;&#x03b3;&#x03eb;&#x03b9;
+ * &#x03bc;&#x03b1;&#x03b2;&#x03bf;&#x03c4;/&#xfeae;&#xfef4;&#xfed0;&#xfebc;&#xfedf;&#x0627;
+ * &#xfeae;&#xfeec;&#xfeb8;&#xfedf;&#x0627;,
+ * the 13th month of the Coptic year.
+ */
+ NASIE
+ };
+
+ enum EEras {
+ BCE, // Before the epoch
+ CE // After the epoch
+ };
+
+ /**
+ * Constructs a CopticCalendar 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 CopticCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ CopticCalendar(const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ CopticCalendar (const CopticCalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~CopticCalendar();
+
+ /**
+ * 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 calendar type, "coptic"
+ * @return calendar type
+ * @internal
+ */
+ const char * getType() const;
+
+protected:
+ //-------------------------------------------------------------------------
+ // Calendar framework
+ //-------------------------------------------------------------------------
+
+ /**
+ * Return the extended year defined by the current fields.
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * Compute fields from the JD
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ /**
+ * 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;
+
+ /**
+ * Return the date offset from Julian
+ * @internal
+ */
+ virtual int32_t getJDEpochOffset() 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;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * 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);
+
+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);
+
+#if 0
+ // We do not want to introduce this API in ICU4C.
+ // It was accidentally introduced in ICU4J as a public API.
+public:
+ //-------------------------------------------------------------------------
+ // Calendar system Conversion methods...
+ //-------------------------------------------------------------------------
+ /**
+ * Convert an Coptic year, month, and day to a Julian day.
+ *
+ * @param year the extended year
+ * @param month the month
+ * @param day the day
+ * @return Julian day
+ * @internal
+ */
+ static int32_t copticToJD(int32_t year, int32_t month, int32_t day);
+#endif
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* COPTCCAL_H */
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.cpp
new file mode 100644
index 00000000000..ebe5d44bf6c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.cpp
@@ -0,0 +1,616 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2008, 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 = 0;
+ UBool failed = FALSE;
+ if (trans != NULL) {
+ for (i=0; i<count; ++i) {
+ delete trans[i];
+ trans[i] = 0;
+ }
+ }
+ if (t.count > count) {
+ if (trans != NULL) {
+ uprv_free(trans);
+ }
+ trans = (Transliterator **)uprv_malloc(t.count * sizeof(Transliterator *));
+ }
+ count = t.count;
+ if (trans != NULL) {
+ for (i=0; i<count; ++i) {
+ trans[i] = t.trans[i]->clone();
+ if (trans[i] == NULL) {
+ failed = TRUE;
+ break;
+ }
+ }
+ }
+
+ // if memory allocation failed delete backwards trans array
+ if (failed && i > 0) {
+ int32_t n;
+ for (n = i-1; n >= 0; n--) {
+ uprv_free(trans[n]);
+ trans[n] = NULL;
+ }
+ }
+ 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 *));
+ if (a == NULL) {
+ return;
+ }
+ int32_t i = 0;
+ UBool failed = FALSE;
+ for (i=0; i<transCount; ++i) {
+ a[i] = transliterators[i]->clone();
+ if (a[i] == NULL) {
+ failed = TRUE;
+ break;
+ }
+ }
+ if (failed && i > 0) {
+ int32_t n;
+ for (n = i-1; n >= 0; n--) {
+ uprv_free(a[n]);
+ a[n] = NULL;
+ }
+ return;
+ }
+ 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-4.8.1/i18n/cpdtrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.h
new file mode 100644
index 00000000000..e3464ed0e86
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/cpdtrans.h
@@ -0,0 +1,230 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2011, 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
+ */
+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.
+ */
+ 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
+ */
+ 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.
+ */
+ CompoundTransliterator(const UnicodeString& id,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Destructor.
+ */
+ virtual ~CompoundTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ CompoundTransliterator(const CompoundTransliterator&);
+
+ /**
+ * Transliterator API.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * Returns the number of transliterators in this chain.
+ * @return number of transliterators in this chain.
+ */
+ virtual int32_t getCount(void) const;
+
+ /**
+ * Returns the transliterator at the given index in this chain.
+ * @param idx index into chain, from 0 to <code>getCount() - 1</code>
+ * @return transliterator at the given index
+ */
+ virtual const Transliterator& getTransliterator(int32_t idx) const;
+
+ /**
+ * Sets the transliterators.
+ */
+ void setTransliterators(Transliterator* const transliterators[],
+ int32_t count);
+
+ /**
+ * Adopts the transliterators.
+ */
+ 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.
+ */
+ 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}.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& idx,
+ UBool incremental) const;
+
+public:
+
+ /**
+ * 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();
+
+ /* @internal */
+ static const UChar PASS_STRING[];
+
+private:
+
+ friend class Transliterator;
+ friend class TransliteratorAlias; // to access private ct
+
+ /**
+ * Assignment operator.
+ */
+ 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-4.8.1/i18n/csdetect.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csdetect.cpp
new file mode 100644
index 00000000000..26c0f6c323c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csdetect.cpp
@@ -0,0 +1,414 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2009, 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(),
+
+ new CharsetRecog_IBM424_he_rtl(),
+ new CharsetRecog_IBM424_he_ltr(),
+ new CharsetRecog_IBM420_ar_rtl(),
+ new CharsetRecog_IBM420_ar_ltr()
+ };
+ int32_t rCount = ARRAY_SIZE(tempArray);
+ int32_t r;
+
+ recognizers = NEW_ARRAY(CharsetRecognizer *, rCount);
+
+ if (recognizers == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ } 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_size = rCount;
+ fCSRecognizers = recognizers;
+ }
+ 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(status)), resultArray(NULL),
+ 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);
+
+ // Remove duplicate charsets from the results.
+ // Simple minded, brute force approach - check each entry against all that follow.
+ // The first entry of any duplicated set is the one that should be kept because it will
+ // be the one with the highest confidence rating.
+ // (Duplicate matches have different languages, only the charset is the same)
+ // Because the resultArray contains preallocated CharsetMatch objects, they aren't actually
+ // deleted, just reordered, with the unwanted duplicates placed after the good results.
+ int32_t j, k;
+ for (i=0; i<resultCount; i++) {
+ const char *charSetName = resultArray[i]->getName();
+ for (j=i+1; j<resultCount; ) {
+ if (uprv_strcmp(charSetName, resultArray[j]->getName()) != 0) {
+ // Not a duplicate.
+ j++;
+ } else {
+ // Duplicate entry at index j.
+ CharsetMatch *duplicate = resultArray[j];
+ for (k=j; k<resultCount-1; k++) {
+ resultArray[k] = resultArray[k+1];
+ }
+ resultCount--;
+ resultArray[resultCount] = duplicate;
+ }
+ }
+ }
+
+ 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-4.8.1/i18n/csdetect.h b/Build/source/libs/icu/icu-4.8.1/i18n/csdetect.h
new file mode 100644
index 00000000000..405e1f55800
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csmatch.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csmatch.cpp
new file mode 100644
index 00000000000..f1d25d2dde9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csmatch.h b/Build/source/libs/icu/icu-4.8.1/i18n/csmatch.h
new file mode 100644
index 00000000000..50b78a3a1dc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csr2022.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csr2022.cpp
new file mode 100644
index 00000000000..84d9495057f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csr2022.cpp
@@ -0,0 +1,175 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2009, 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) {
+ const uint8_t *seq = escapeSequences[escN];
+ int32_t seq_length = (int32_t)uprv_strlen((const char *) seq);
+
+ if (textLen-i >= seq_length) {
+ j = 1;
+ while(j < seq_length) {
+ if(seq[j] != text[i+j]) {
+ goto checkEscapes;
+ }
+
+ j += 1;
+ }
+
+ hits += 1;
+ i += seq_length-1;
+ goto scanInput;
+ }
+ // else we ran out of string to compare this time.
+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-4.8.1/i18n/csr2022.h b/Build/source/libs/icu/icu-4.8.1/i18n/csr2022.h
new file mode 100644
index 00000000000..5d34711bdc3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csrecog.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csrecog.cpp
new file mode 100644
index 00000000000..ba70b1547f8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csrecog.h b/Build/source/libs/icu/icu-4.8.1/i18n/csrecog.h
new file mode 100644
index 00000000000..75cf94f49f4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csrmbcs.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csrmbcs.cpp
new file mode 100644
index 00000000000..6252a2b8254
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csrmbcs.cpp
@@ -0,0 +1,519 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2011, 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))
+
+static const uint16_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};
+
+static const uint16_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};
+
+static const uint16_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};
+
+static const uint16_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};
+
+static const uint16_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 uint16_t *array, int32_t len, uint16_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(-1), 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 uint16_t commonChars[], int32_t commonCharsLen) {
+ int32_t singleByteCharCount = 0;
+ int32_t doubleByteCharCount = 0;
+ int32_t commonCharCount = 0;
+ int32_t badCharCount = 0;
+ int32_t totalCharCount = 0;
+ int32_t confidence = 0;
+ IteratedChar iter;
+
+ while (nextChar(&iter, det)) {
+ totalCharCount++;
+
+ if (iter.error) {
+ badCharCount++;
+ } else {
+ if (iter.charValue <= 0xFF) {
+ singleByteCharCount++;
+ } else {
+ doubleByteCharCount++;
+
+ 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;
+ return confidence;
+ }
+ }
+
+ if (doubleByteCharCount <= 10 && badCharCount == 0) {
+ // Not many multi-byte chars.
+ if (doubleByteCharCount == 0 && totalCharCount < 10) {
+ // There weren't any multibyte sequences, and there was a low density of non-ASCII single bytes.
+ // We don't have enough data to have any confidence.
+ // Statistical analysis of single byte non-ASCII charcters would probably help here.
+ confidence = 0;
+ }
+ else {
+ // 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 = log((double)doubleByteCharCount / 4); /*(float)?*/
+ double scaleFactor = 90.0 / maxVal;
+ confidence = (int32_t)(log((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) {
+ it->charValue = (firstByte << 8) | secondByte;
+ }
+ // else we'll handle the error later.
+
+ 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;
+
+ it->index = it->nextIndex;
+ it->error = FALSE;
+ firstByte = it->charValue = it->nextByte(det);
+
+ if (firstByte < 0) {
+ // Ran off the end of the input data
+ return FALSE;
+ }
+
+ if (firstByte <= 0x8D) {
+ // single byte char
+ return TRUE;
+ }
+
+ secondByte = it->nextByte(det);
+ if (secondByte >= 0) {
+ it->charValue = (it->charValue << 8) | secondByte;
+ }
+ // else we'll handle the error later.
+
+ if (firstByte >= 0xA1 && firstByte <= 0xFE) {
+ // Two byte Char
+ if (secondByte < 0xA1) {
+ it->error = TRUE;
+ }
+
+ return TRUE;
+ }
+
+ 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 TRUE;
+ }
+
+ 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) {
+ // Bad second byte or ran off the end of the input data with a non-ASCII first byte.
+ it->error = TRUE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+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) {
+ it->charValue = (it->charValue << 8) | secondByte;
+ }
+ // else we'll handle the error later.
+
+ 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
+ return FALSE;
+ }
+
+ if (firstByte <= 0x80) {
+ // single byte char
+ return TRUE;
+ }
+
+ secondByte = it->nextByte(det);
+ if (secondByte >= 0) {
+ it->charValue = (it->charValue << 8) | secondByte;
+ }
+ // else we'll handle the error later.
+
+ if (firstByte >= 0x81 && firstByte <= 0xFE) {
+ // Two byte Char
+ if ((secondByte >= 0x40 && secondByte <= 0x7E) || (secondByte >=80 && secondByte <= 0xFE)) {
+ return TRUE;
+ }
+
+ // 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 TRUE;
+ }
+ }
+ }
+
+ // Something wasn't valid, or we ran out of data (-1).
+ it->error = TRUE;
+ }
+
+ return TRUE;
+}
+
+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-4.8.1/i18n/csrmbcs.h b/Build/source/libs/icu/icu-4.8.1/i18n/csrmbcs.h
new file mode 100644
index 00000000000..371889a1e61
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csrmbcs.h
@@ -0,0 +1,205 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2008, 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 uint16_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-4.8.1/i18n/csrsbcs.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.cpp
new file mode 100644
index 00000000000..5b55af64751
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.cpp
@@ -0,0 +1,1350 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2010, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#include "cmemory.h"
+
+#if !UCONFIG_NO_CONVERSION
+#include "csrsbcs.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(ngrams, byteMap);
+ int32_t result;
+
+ haveC1Bytes = det->fC1Bytes;
+ result = parser.parse(det);
+
+ 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,
+};
+
+static const int32_t ngrams_IBM424_he_rtl[] = {
+ 0x404146, 0x404148, 0x404151, 0x404171, 0x404251, 0x404256, 0x404541, 0x404546, 0x404551, 0x404556, 0x404562, 0x404569, 0x404571, 0x405441, 0x405445, 0x405641,
+ 0x406254, 0x406954, 0x417140, 0x454041, 0x454042, 0x454045, 0x454054, 0x454056, 0x454069, 0x454641, 0x464140, 0x465540, 0x465740, 0x466840, 0x467140, 0x514045,
+ 0x514540, 0x514671, 0x515155, 0x515540, 0x515740, 0x516840, 0x517140, 0x544041, 0x544045, 0x544140, 0x544540, 0x554041, 0x554042, 0x554045, 0x554054, 0x554056,
+ 0x554069, 0x564540, 0x574045, 0x584540, 0x585140, 0x585155, 0x625440, 0x684045, 0x685155, 0x695440, 0x714041, 0x714042, 0x714045, 0x714054, 0x714056, 0x714069,
+};
+
+static const int32_t ngrams_IBM424_he_ltr[] = {
+ 0x404146, 0x404154, 0x404551, 0x404554, 0x404556, 0x404558, 0x405158, 0x405462, 0x405469, 0x405546, 0x405551, 0x405746, 0x405751, 0x406846, 0x406851, 0x407141,
+ 0x407146, 0x407151, 0x414045, 0x414054, 0x414055, 0x414071, 0x414540, 0x414645, 0x415440, 0x415640, 0x424045, 0x424055, 0x424071, 0x454045, 0x454051, 0x454054,
+ 0x454055, 0x454057, 0x454068, 0x454071, 0x455440, 0x464140, 0x464540, 0x484140, 0x514140, 0x514240, 0x514540, 0x544045, 0x544055, 0x544071, 0x546240, 0x546940,
+ 0x555151, 0x555158, 0x555168, 0x564045, 0x564055, 0x564071, 0x564240, 0x564540, 0x624540, 0x694045, 0x694055, 0x694071, 0x694540, 0x714140, 0x714540, 0x714651,
+};
+
+static const uint8_t charMap_IBM424_he[] = {
+/* -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F */
+/* 0- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 1- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 2- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 3- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 4- */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 5- */ 0x40, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 6- */ 0x40, 0x40, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 7- */ 0x40, 0x71, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40,
+/* 8- */ 0x40, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 9- */ 0x40, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* A- */ 0xA0, 0x40, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* B- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* C- */ 0x40, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* D- */ 0x40, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* E- */ 0x40, 0x40, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* F- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+};
+
+static const int32_t ngrams_IBM420_ar_rtl[] = {
+ 0x4056B1, 0x4056BD, 0x405856, 0x409AB1, 0x40ABDC, 0x40B1B1, 0x40BBBD, 0x40CF56, 0x564056, 0x564640, 0x566340, 0x567540, 0x56B140, 0x56B149, 0x56B156, 0x56B158,
+ 0x56B163, 0x56B167, 0x56B169, 0x56B173, 0x56B178, 0x56B19A, 0x56B1AD, 0x56B1BB, 0x56B1CF, 0x56B1DC, 0x56BB40, 0x56BD40, 0x56BD63, 0x584056, 0x624056, 0x6240AB,
+ 0x6240B1, 0x6240BB, 0x6240CF, 0x634056, 0x734056, 0x736240, 0x754056, 0x756240, 0x784056, 0x9A4056, 0x9AB1DA, 0xABDC40, 0xB14056, 0xB16240, 0xB1DA40, 0xB1DC40,
+ 0xBB4056, 0xBB5640, 0xBB6240, 0xBBBD40, 0xBD4056, 0xBF4056, 0xBF5640, 0xCF56B1, 0xCFBD40, 0xDA4056, 0xDC4056, 0xDC40BB, 0xDC40CF, 0xDC6240, 0xDC7540, 0xDCBD40,
+};
+
+static const int32_t ngrams_IBM420_ar_ltr[] = {
+ 0x404656, 0x4056BB, 0x4056BF, 0x406273, 0x406275, 0x4062B1, 0x4062BB, 0x4062DC, 0x406356, 0x407556, 0x4075DC, 0x40B156, 0x40BB56, 0x40BD56, 0x40BDBB, 0x40BDCF,
+ 0x40BDDC, 0x40DAB1, 0x40DCAB, 0x40DCB1, 0x49B156, 0x564056, 0x564058, 0x564062, 0x564063, 0x564073, 0x564075, 0x564078, 0x56409A, 0x5640B1, 0x5640BB, 0x5640BD,
+ 0x5640BF, 0x5640DA, 0x5640DC, 0x565840, 0x56B156, 0x56CF40, 0x58B156, 0x63B156, 0x63BD56, 0x67B156, 0x69B156, 0x73B156, 0x78B156, 0x9AB156, 0xAB4062, 0xADB156,
+ 0xB14062, 0xB15640, 0xB156CF, 0xB19A40, 0xB1B140, 0xBB4062, 0xBB40DC, 0xBBB156, 0xBD5640, 0xBDBB40, 0xCF4062, 0xCF40DC, 0xCFB156, 0xDAB19A, 0xDCAB40, 0xDCB156
+};
+
+static const uint8_t charMap_IBM420_ar[]= {
+/* -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F */
+/* 0- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 1- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 2- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 3- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 4- */ 0x40, 0x40, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 5- */ 0x40, 0x51, 0x52, 0x40, 0x40, 0x55, 0x56, 0x57, 0x58, 0x59, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 6- */ 0x40, 0x40, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 7- */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 8- */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+/* 9- */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+/* A- */ 0xA0, 0x40, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+/* B- */ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0x40, 0x40, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+/* C- */ 0x40, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x40, 0xCB, 0x40, 0xCD, 0x40, 0xCF,
+/* D- */ 0x40, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+/* E- */ 0x40, 0x40, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xEA, 0xEB, 0x40, 0xED, 0xEE, 0xEF,
+/* F- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xFB, 0xFC, 0xFD, 0xFE, 0x40,
+};
+
+//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);
+}
+
+CharsetRecog_IBM424_he::~CharsetRecog_IBM424_he()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_IBM424_he::getLanguage() const
+{
+ return "he";
+}
+
+CharsetRecog_IBM424_he_rtl::~CharsetRecog_IBM424_he_rtl()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_IBM424_he_rtl::getName() const
+{
+ return "IBM424_rtl";
+}
+
+int32_t CharsetRecog_IBM424_he_rtl::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_IBM424_he_rtl, charMap_IBM424_he);
+}
+
+CharsetRecog_IBM424_he_ltr::~CharsetRecog_IBM424_he_ltr()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_IBM424_he_ltr::getName() const
+{
+ return "IBM424_ltr";
+}
+
+int32_t CharsetRecog_IBM424_he_ltr::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_IBM424_he_ltr, charMap_IBM424_he);
+}
+
+static const uint8_t unshapeMap_IBM420[] = {
+/* -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F */
+/* 0- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 1- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 2- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 3- */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+/* 4- */ 0x40, 0x40, 0x42, 0x42, 0x44, 0x45, 0x46, 0x47, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+/* 5- */ 0x50, 0x49, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x58, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+/* 6- */ 0x60, 0x61, 0x62, 0x63, 0x63, 0x65, 0x65, 0x67, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+/* 7- */ 0x69, 0x71, 0x71, 0x73, 0x74, 0x75, 0x76, 0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+/* 8- */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x80, 0x8B, 0x8B, 0x8D, 0x8D, 0x8F,
+/* 9- */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9E, 0x9E,
+/* A- */ 0x9E, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x9E, 0xAB, 0xAB, 0xAD, 0xAD, 0xAF,
+/* B- */ 0xAF, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xB1, 0xBB, 0xBB, 0xBD, 0xBD, 0xBF,
+/* C- */ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xBF, 0xCC, 0xBF, 0xCE, 0xCF,
+/* D- */ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDC, 0xDF,
+/* E- */ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+/* F- */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+};
+
+CharsetRecog_IBM420_ar::~CharsetRecog_IBM420_ar()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_IBM420_ar::getLanguage() const
+{
+ return "ar";
+}
+
+void CharsetRecog_IBM420_ar::matchInit(InputText *textIn) {
+ prev_fInputBytesLength = textIn->fInputLen;
+ prev_fInputBytes = textIn->fInputBytes;
+
+ int32_t length = 0;
+ uint8_t *bb = unshape(prev_fInputBytes, prev_fInputBytesLength, length);
+
+ if (bb != NULL) {
+ textIn->fInputBytes = bb;
+ textIn->fInputLen = length;
+
+ deleteBuffer = TRUE;
+ } else {
+ deleteBuffer = FALSE;
+ }
+}
+
+uint8_t *CharsetRecog_IBM420_ar::unshape(const uint8_t *inputBytes, int32_t inputBytesLength, int32_t &length) {
+ uint8_t *resultArray = unshapeLamAlef(inputBytes, inputBytesLength, length);
+
+ if (resultArray != NULL) {
+ for (int32_t i = 0; i < inputBytesLength; i++) {
+ resultArray[i] = unshapeMap_IBM420[resultArray[i]];
+ }
+ }
+
+ return resultArray;
+}
+
+uint8_t *CharsetRecog_IBM420_ar::unshapeLamAlef(const uint8_t *inputBytes, int32_t inputBytesLength, int32_t &length) {
+ int32_t bigBufferLength = inputBytesLength * 2;
+ uint8_t *bigBuffer = (uint8_t *)uprv_malloc(bigBufferLength);
+ uint8_t *resultBuffer = NULL;
+
+ if (bigBuffer != NULL) {
+ int32_t bufferIndex;
+ uint8_t unshapedLamAlef[] = { 0xb1, 0x56 };
+
+ for (int32_t i = bufferIndex = 0; i < inputBytesLength; i++) {
+ if (isLamAlef(inputBytes[i])) {
+ bigBuffer[bufferIndex++] = unshapedLamAlef[0];
+ bigBuffer[bufferIndex++] = unshapedLamAlef[1];
+ } else {
+ bigBuffer[bufferIndex++] = inputBytes[i];
+ }
+ }
+
+ length = bufferIndex;
+ resultBuffer = (uint8_t *)uprv_malloc(length);
+ if (resultBuffer != NULL) {
+ uprv_memcpy(resultBuffer, bigBuffer, length);
+ }
+ }
+
+ if (bigBuffer != NULL) {
+ uprv_free(bigBuffer);
+ }
+
+ return resultBuffer;
+}
+
+void CharsetRecog_IBM420_ar::matchFinish(InputText *textIn) {
+ if (deleteBuffer) {
+ uprv_free(textIn->fInputBytes);
+
+ textIn->fInputBytes = prev_fInputBytes;
+ textIn->fInputLen = prev_fInputBytesLength;
+ }
+}
+
+UBool CharsetRecog_IBM420_ar::isLamAlef(uint8_t b) {
+ uint8_t shapedLamAlef[] = {
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb7, 0xb8
+ };
+
+ for (uint32_t i = 0; i < sizeof(shapedLamAlef); i++) {
+ if (b == shapedLamAlef[i]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+CharsetRecog_IBM420_ar_rtl::~CharsetRecog_IBM420_ar_rtl()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_IBM420_ar_rtl::getName() const
+{
+ return "IBM420_rtl";
+}
+
+int32_t CharsetRecog_IBM420_ar_rtl::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_IBM420_ar_rtl, charMap_IBM420_ar);
+}
+
+CharsetRecog_IBM420_ar_ltr::~CharsetRecog_IBM420_ar_ltr()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_IBM420_ar_ltr::getName() const
+{
+ return "IBM420_ltr";
+}
+
+int32_t CharsetRecog_IBM420_ar_ltr::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_IBM420_ar_ltr, charMap_IBM420_ar);
+}
+
+U_NAMESPACE_END
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.h b/Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.h
new file mode 100644
index 00000000000..21cbabe5663
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csrsbcs.h
@@ -0,0 +1,427 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2009, 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);
+};
+
+class CharsetRecog_IBM424_he : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_IBM424_he();
+
+ const char *getLanguage() const;
+};
+
+class CharsetRecog_IBM424_he_rtl : public CharsetRecog_IBM424_he {
+public:
+ virtual ~CharsetRecog_IBM424_he_rtl();
+
+ const char *getName() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_IBM424_he_ltr : public CharsetRecog_IBM424_he {
+ virtual ~CharsetRecog_IBM424_he_ltr();
+
+ const char *getName() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_IBM420_ar : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_IBM420_ar();
+
+ const char *getLanguage() const;
+
+protected:
+ void matchInit(InputText *textIn);
+ void matchFinish(InputText *textIn);
+
+private:
+ uint8_t *prev_fInputBytes;
+ int32_t prev_fInputBytesLength;
+ UBool deleteBuffer;
+
+ UBool isLamAlef(uint8_t b);
+ uint8_t *unshapeLamAlef(const uint8_t *inputBytes, int32_t inputBytesLength, int32_t &length);
+ uint8_t *unshape(const uint8_t *inputBytes, int32_t inputBytesLength, int32_t &length);
+};
+
+class CharsetRecog_IBM420_ar_rtl : public CharsetRecog_IBM420_ar {
+public:
+ virtual ~CharsetRecog_IBM420_ar_rtl();
+
+ const char *getName() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_IBM420_ar_ltr : public CharsetRecog_IBM420_ar {
+ virtual ~CharsetRecog_IBM420_ar_ltr();
+
+ const char *getName() const;
+
+ int32_t match(InputText *textIn);
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSRSBCS_H */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/csrucode.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csrucode.cpp
new file mode 100644
index 00000000000..99a76d850e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csrucode.h b/Build/source/libs/icu/icu-4.8.1/i18n/csrucode.h
new file mode 100644
index 00000000000..315bad6b25e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/csrutf8.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/csrutf8.cpp
new file mode 100644
index 00000000000..b87c277fbf9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/csrutf8.cpp
@@ -0,0 +1,111 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2008, 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-4.8.1/i18n/csrutf8.h b/Build/source/libs/icu/icu-4.8.1/i18n/csrutf8.h
new file mode 100644
index 00000000000..10fe287a435
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/curramt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/curramt.cpp
new file mode 100644
index 00000000000..f4e1abb0572
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/currfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/currfmt.cpp
new file mode 100644
index 00000000000..133497154b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/currfmt.cpp
@@ -0,0 +1,72 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 20, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include <typeinfo> // for 'typeid' to work
+
+#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 (typeid(*this) != typeid(other)) {
+ 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-4.8.1/i18n/currfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/currfmt.h
new file mode 100644
index 00000000000..82aae3ec050
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/currfmt.h
@@ -0,0 +1,101 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2010, 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 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;
+
+
+ using MeasureFormat::format;
+
+ /**
+ * 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-4.8.1/i18n/currpinf.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/currpinf.cpp
new file mode 100644
index 00000000000..e80d84702b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/currpinf.cpp
@@ -0,0 +1,388 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2011, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#include "unicode/currpinf.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+//#define CURRENCY_PLURAL_INFO_DEBUG 1
+
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+#include <iostream>
+#endif
+
+
+#include "unicode/locid.h"
+#include "unicode/plurrule.h"
+#include "unicode/ures.h"
+#include "cstring.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+
+U_NAMESPACE_BEGIN
+
+
+static const UChar gNumberPatternSeparator = 0x3B; // ;
+
+U_CDECL_BEGIN
+
+/**
+ * @internal ICU 4.2
+ */
+static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
+
+UBool
+U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
+ const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
+ const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
+ return *affix_1 == *affix_2;
+}
+
+U_CDECL_END
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
+
+static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
+static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
+static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
+static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
+static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
+
+static const char gNumberElementsTag[]="NumberElements";
+static const char gLatnTag[]="latn";
+static const char gPatternsTag[]="patterns";
+static const char gDecimalFormatTag[]="decimalFormat";
+static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
+
+CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
+: fPluralCountToCurrencyUnitPattern(NULL),
+ fPluralRules(NULL),
+ fLocale(NULL) {
+ initialize(Locale::getDefault(), status);
+}
+
+CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
+: fPluralCountToCurrencyUnitPattern(NULL),
+ fPluralRules(NULL),
+ fLocale(NULL) {
+ initialize(locale, status);
+}
+
+CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
+: UObject(info),
+ fPluralCountToCurrencyUnitPattern(NULL),
+ fPluralRules(NULL),
+ fLocale(NULL) {
+ *this = info;
+}
+
+
+CurrencyPluralInfo&
+CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
+ if (this == &info) {
+ return *this;
+ }
+
+ deleteHash(fPluralCountToCurrencyUnitPattern);
+ UErrorCode status = U_ZERO_ERROR;
+ fPluralCountToCurrencyUnitPattern = initHash(status);
+ copyHash(info.fPluralCountToCurrencyUnitPattern,
+ fPluralCountToCurrencyUnitPattern, status);
+ if ( U_FAILURE(status) ) {
+ return *this;
+ }
+
+ delete fPluralRules;
+ delete fLocale;
+ if (info.fPluralRules) {
+ fPluralRules = info.fPluralRules->clone();
+ } else {
+ fPluralRules = NULL;
+ }
+ if (info.fLocale) {
+ fLocale = info.fLocale->clone();
+ } else {
+ fLocale = NULL;
+ }
+ return *this;
+}
+
+
+CurrencyPluralInfo::~CurrencyPluralInfo() {
+ deleteHash(fPluralCountToCurrencyUnitPattern);
+ fPluralCountToCurrencyUnitPattern = NULL;
+ delete fPluralRules;
+ delete fLocale;
+ fPluralRules = NULL;
+ fLocale = NULL;
+}
+
+UBool
+CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ if (*fPluralRules == *info.fPluralRules) {
+ std::cout << "same plural rules\n";
+ }
+ if (*fLocale == *info.fLocale) {
+ std::cout << "same locale\n";
+ }
+ if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
+ std::cout << "same pattern\n";
+ }
+#endif
+ return *fPluralRules == *info.fPluralRules &&
+ *fLocale == *info.fLocale &&
+ fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
+}
+
+
+CurrencyPluralInfo*
+CurrencyPluralInfo::clone() const {
+ return new CurrencyPluralInfo(*this);
+}
+
+const PluralRules*
+CurrencyPluralInfo::getPluralRules() const {
+ return fPluralRules;
+}
+
+UnicodeString&
+CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
+ UnicodeString& result) const {
+ const UnicodeString* currencyPluralPattern =
+ (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
+ if (currencyPluralPattern == NULL) {
+ // fall back to "other"
+ if (pluralCount.compare(gPluralCountOther, 5)) {
+ currencyPluralPattern =
+ (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
+ }
+ if (currencyPluralPattern == NULL) {
+ // no currencyUnitPatterns defined,
+ // fallback to predefined defult.
+ // This should never happen when ICU resource files are
+ // available, since currencyUnitPattern of "other" is always
+ // defined in root.
+ result = UnicodeString(gDefaultCurrencyPluralPattern);
+ return result;
+ }
+ }
+ result = *currencyPluralPattern;
+ return result;
+}
+
+const Locale&
+CurrencyPluralInfo::getLocale() const {
+ return *fLocale;
+}
+
+void
+CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
+ UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ if (fPluralRules) {
+ delete fPluralRules;
+ }
+ fPluralRules = PluralRules::createRules(ruleDescription, status);
+ }
+}
+
+
+void
+CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
+ const UnicodeString& pattern,
+ UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
+ }
+}
+
+
+void
+CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
+ initialize(loc, status);
+}
+
+
+void
+CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ delete fLocale;
+ fLocale = loc.clone();
+ if (fPluralRules) {
+ delete fPluralRules;
+ }
+ fPluralRules = PluralRules::forLocale(loc, status);
+ setupCurrencyPluralPattern(loc, status);
+}
+
+
+void
+CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (fPluralCountToCurrencyUnitPattern) {
+ deleteHash(fPluralCountToCurrencyUnitPattern);
+ }
+ fPluralCountToCurrencyUnitPattern = initHash(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
+ rb = ures_getByKeyWithFallback(rb, gNumberElementsTag, rb, &ec);
+ rb = ures_getByKeyWithFallback(rb, gLatnTag, rb, &ec);
+ rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
+ int32_t ptnLen;
+ const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
+ int32_t numberStylePatternLen = ptnLen;
+ const UChar* negNumberStylePattern = NULL;
+ int32_t negNumberStylePatternLen = 0;
+ // TODO: Java
+ // parse to check whether there is ";" separator in the numberStylePattern
+ UBool hasSeparator = false;
+ if (U_SUCCESS(ec)) {
+ for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) {
+ if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) {
+ hasSeparator = true;
+ // split the number style pattern into positive and negative
+ negNumberStylePattern = numberStylePattern + styleCharIndex + 1;
+ negNumberStylePatternLen = ptnLen - styleCharIndex - 1;
+ numberStylePatternLen = styleCharIndex;
+ }
+ }
+ }
+ ures_close(rb);
+
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec);
+ UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec);
+
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ std::cout << "in set up\n";
+#endif
+ StringEnumeration* keywords = fPluralRules->getKeywords(ec);
+ if (U_SUCCESS(ec)) {
+ const char* pluralCount;
+ while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
+ if ( U_SUCCESS(ec) ) {
+ int32_t ptnLen;
+ UErrorCode err = U_ZERO_ERROR;
+ const UChar* patternChars = ures_getStringByKeyWithFallback(
+ currencyRes, pluralCount, &ptnLen, &err);
+ if (U_SUCCESS(err) && ptnLen > 0) {
+ UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ char result_1[1000];
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+#endif
+ pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
+ UnicodeString(numberStylePattern, numberStylePatternLen));
+ pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
+
+ if (hasSeparator) {
+ UnicodeString negPattern(patternChars, ptnLen);
+ negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
+ UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
+ negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
+ pattern->append(gNumberPatternSeparator);
+ pattern->append(negPattern);
+ }
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+#endif
+
+ fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
+ }
+ }
+ }
+ }
+ delete keywords;
+ ures_close(currencyRes);
+ ures_close(currRb);
+}
+
+
+
+void
+CurrencyPluralInfo::deleteHash(Hashtable* hTable)
+{
+ if ( hTable == NULL ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = hTable->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ delete value;
+ }
+ delete hTable;
+ hTable = NULL;
+}
+
+
+Hashtable*
+CurrencyPluralInfo::initHash(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if ( U_FAILURE(status) ) {
+ delete hTable;
+ return NULL;
+ }
+ hTable->setValueComparator(ValueComparator);
+ return hTable;
+}
+
+
+void
+CurrencyPluralInfo::copyHash(const Hashtable* source,
+ Hashtable* target,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ UnicodeString* copy = new UnicodeString(*value);
+ target->put(UnicodeString(*key), copy, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/currunit.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/currunit.cpp
new file mode 100644
index 00000000000..47cba6253aa
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/currunit.cpp
@@ -0,0 +1,62 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include <typeinfo> // for 'typeid' to work
+
+#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 typeid(*this) == typeid(other) &&
+ 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-4.8.1/i18n/datefmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/datefmt.cpp
new file mode 100644
index 00000000000..ad3555714d1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/datefmt.cpp
@@ -0,0 +1,513 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2011, 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 "unicode/dtptngen.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(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ 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, posIter, status);
+}
+
+//----------------------------------------------------------------------
+
+// Default implementation for backwards compatibility, subclasses should implement.
+UnicodeString&
+DateFormat::format(Calendar& /* unused cal */,
+ UnicodeString& appendTo,
+ FieldPositionIterator* /* unused posIter */,
+ UErrorCode& status) const {
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return appendTo;
+}
+
+//----------------------------------------------------------------------
+
+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, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (fCalendar != NULL) {
+ fCalendar->setTime(date, status);
+ if (U_SUCCESS(status)) {
+ return format(*fCalendar, appendTo, posIter, status);
+ }
+ }
+ 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)
+{
+ Calendar* newCalClone = newCalendar.clone();
+ if (newCalClone != NULL) {
+ adoptCalendar(newCalClone);
+ }
+}
+
+//----------------------------------------------------------------------
+
+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)
+{
+ NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
+ if (newNumFmtClone != NULL) {
+ adoptNumberFormat(newNumFmtClone);
+ }
+}
+
+//----------------------------------------------------------------------
+
+const NumberFormat*
+DateFormat::getNumberFormat() const
+{
+ return fNumberFormat;
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::adoptTimeZone(TimeZone* zone)
+{
+ if (fCalendar != NULL) {
+ fCalendar->adoptTimeZone(zone);
+ }
+}
+//----------------------------------------------------------------------
+
+void
+DateFormat::setTimeZone(const TimeZone& zone)
+{
+ if (fCalendar != NULL) {
+ fCalendar->setTimeZone(zone);
+ }
+}
+
+//----------------------------------------------------------------------
+
+const TimeZone&
+DateFormat::getTimeZone() const
+{
+ if (fCalendar != NULL) {
+ return fCalendar->getTimeZone();
+ }
+ // If calendar doesn't exists, create default timezone.
+ // fCalendar is rarely null
+ return *(TimeZone::createDefault());
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::setLenient(UBool lenient)
+{
+ if (fCalendar != NULL) {
+ fCalendar->setLenient(lenient);
+ }
+}
+
+//----------------------------------------------------------------------
+
+UBool
+DateFormat::isLenient() const
+{
+ if (fCalendar != NULL) {
+ return fCalendar->isLenient();
+ }
+ // fCalendar is rarely null
+ return FALSE;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/dcfmtsym.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/dcfmtsym.cpp
new file mode 100644
index 00000000000..cc537830ec7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dcfmtsym.cpp
@@ -0,0 +1,450 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 "unicode/unistr.h"
+#include "unicode/numsys.h"
+#include "unicode/unum.h"
+#include "ucurrimp.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+
+// *****************************************************************************
+// class DecimalFormatSymbols
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols)
+
+static const char gNumberElements[] = "NumberElements";
+static const char gCurrencySpacingTag[] = "currencySpacing";
+static const char gBeforeCurrencyTag[] = "beforeCurrency";
+static const char gAfterCurrencyTag[] = "afterCurrency";
+static const char gCurrencyMatchTag[] = "currencyMatch";
+static const char gCurrencySudMatchTag[] = "surroundingMatch";
+static const char gCurrencyInsertBtnTag[] = "insertBetween";
+
+
+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]);
+ }
+ for(int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; ++i) {
+ currencySpcBeforeSym[i].fastCopyFrom(rhs.currencySpcBeforeSym[i]);
+ currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[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;
+ }
+ }
+ for(int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; ++i) {
+ if(currencySpcBeforeSym[i] != that.currencySpcBeforeSym[i]) {
+ return FALSE;
+ }
+ if(currencySpcAfterSym[i] != that.currencySpcAfterSym[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)
+{
+ static const char *gNumberElementKeys[kFormatSymbolCount] = {
+ "decimal",
+ "group",
+ "list",
+ "percentSign",
+ NULL, /* Native zero digit is deprecated from CLDR - get it from the numbering system */
+ NULL, /* Pattern digit character is deprecated from CLDR - use # by default always */
+ "minusSign",
+ "plusSign",
+ NULL, /* currency symbol - We don't really try to load this directly from CLDR until we know the currency */
+ NULL, /* intl currency symbol - We don't really try to load this directly from CLDR until we know the currency */
+ "currencyDecimal",
+ "exponential",
+ "perMille",
+ NULL, /* Escape padding character - not in CLDR */
+ "infinity",
+ "nan",
+ NULL, /* Significant digit symbol - not in CLDR */
+ "currencyGroup",
+ NULL, /* one digit - get it from the numbering system */
+ NULL, /* two digit - get it from the numbering system */
+ NULL, /* three digit - get it from the numbering system */
+ NULL, /* four digit - get it from the numbering system */
+ NULL, /* five digit - get it from the numbering system */
+ NULL, /* six digit - get it from the numbering system */
+ NULL, /* seven digit - get it from the numbering system */
+ NULL, /* eight digit - get it from the numbering system */
+ NULL, /* nine digit - get it from the numbering system */
+ };
+
+ static const char *gLatn = "latn";
+ static const char *gSymbols = "symbols";
+ const char *nsName;
+ const UChar *sym = NULL;
+ int32_t len = 0;
+
+ *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_getByKeyWithFallback(resource, gNumberElements, NULL, &status);
+
+ if (U_FAILURE(status)) {
+ if ( useLastResortData ) {
+ status = U_USING_FALLBACK_WARNING;
+ initialize();
+ }
+ return;
+ } else {
+
+ // First initialize all the symbols to the fallbacks for anything we can't find
+ initialize();
+
+ //
+ // Next get the numbering system for this locale and set zero digit
+ // and the digit string based on the numbering system for the locale
+ //
+
+ NumberingSystem* ns = NumberingSystem::createInstance(loc,status);
+ if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) {
+ nsName = ns->getName();
+ UnicodeString *DigitString = new UnicodeString(ns->getDescription());
+ setSymbol(kZeroDigitSymbol,DigitString->charAt(0),FALSE);
+ setSymbol(kOneDigitSymbol,DigitString->charAt(1),FALSE);
+ setSymbol(kTwoDigitSymbol,DigitString->charAt(2),FALSE);
+ setSymbol(kThreeDigitSymbol,DigitString->charAt(3),FALSE);
+ setSymbol(kFourDigitSymbol,DigitString->charAt(4),FALSE);
+ setSymbol(kFiveDigitSymbol,DigitString->charAt(5),FALSE);
+ setSymbol(kSixDigitSymbol,DigitString->charAt(6),FALSE);
+ setSymbol(kSevenDigitSymbol,DigitString->charAt(7),FALSE);
+ setSymbol(kEightDigitSymbol,DigitString->charAt(8),FALSE);
+ setSymbol(kNineDigitSymbol,DigitString->charAt(9),FALSE);
+ delete DigitString;
+ } else {
+ nsName = gLatn;
+ }
+
+ UBool isLatn = !uprv_strcmp(nsName,gLatn);
+
+ UErrorCode nlStatus = U_ZERO_ERROR;
+ UResourceBundle *nonLatnSymbols = NULL;
+ if ( !isLatn ) {
+ nonLatnSymbols = ures_getByKeyWithFallback(numberElementsRes, nsName, NULL, &nlStatus);
+ nonLatnSymbols = ures_getByKeyWithFallback(nonLatnSymbols, gSymbols, nonLatnSymbols, &nlStatus);
+ }
+
+ UResourceBundle *latnSymbols = ures_getByKeyWithFallback(numberElementsRes, gLatn, NULL, &status);
+ latnSymbols = ures_getByKeyWithFallback(latnSymbols, gSymbols, latnSymbols, &status);
+
+ UBool kMonetaryDecimalSet = FALSE;
+ UBool kMonetaryGroupingSet = FALSE;
+ for(int32_t i = 0; i<kFormatSymbolCount; i++) {
+ if ( gNumberElementKeys[i] != NULL ) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ if ( !isLatn ) {
+ sym = ures_getStringByKeyWithFallback(nonLatnSymbols,gNumberElementKeys[i],&len,&localStatus);
+ // If we can't find the symbol in the numbering system specific resources,
+ // use the "latn" numbering system as the fallback.
+ if ( U_FAILURE(localStatus) ) {
+ localStatus = U_ZERO_ERROR;
+ sym = ures_getStringByKeyWithFallback(latnSymbols,gNumberElementKeys[i],&len,&localStatus);
+ }
+ } else {
+ sym = ures_getStringByKeyWithFallback(latnSymbols,gNumberElementKeys[i],&len,&localStatus);
+ }
+
+ if ( U_SUCCESS(localStatus) ) {
+ setSymbol((ENumberFormatSymbol)i,sym);
+ if ( i == kMonetarySeparatorSymbol ) {
+ kMonetaryDecimalSet = TRUE;
+ } else if ( i == kMonetaryGroupingSeparatorSymbol ) {
+ kMonetaryGroupingSet = TRUE;
+ }
+ }
+ }
+ }
+
+ ures_close(latnSymbols);
+ if ( !isLatn ) {
+ ures_close(nonLatnSymbols);
+ }
+
+ // If monetary decimal or grouping were not explicitly set, then set them to be the
+ // same as their non-monetary counterparts.
+
+ if ( !kMonetaryDecimalSet ) {
+ setSymbol(kMonetarySeparatorSymbol,fSymbols[kDecimalSeparatorSymbol]);
+ }
+ if ( !kMonetaryGroupingSet ) {
+ setSymbol(kMonetaryGroupingSeparatorSymbol,fSymbols[kGroupingSeparatorSymbol]);
+ }
+
+ if (ns) {
+ delete ns;
+ }
+
+ // 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();
+ UErrorCode localStatus = U_ZERO_ERROR;
+ uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus);
+
+ if(U_SUCCESS(localStatus) && uccLen > 0) {
+ char cc[4]={0};
+ u_UCharsToChars(ucc, cc, uccLen);
+ /* An explicit currency was requested */
+ UResourceBundle *currencyResource = ures_open(U_ICUDATA_CURR, locStr, &localStatus);
+ UResourceBundle *currency = ures_getByKeyWithFallback(currencyResource, "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);
+ ures_close(currencyResource);
+ /* 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
+
+ // Currency Spacing.
+ localStatus = U_ZERO_ERROR;
+ UResourceBundle *currencyResource = ures_open(U_ICUDATA_CURR, locStr, &localStatus);
+ UResourceBundle *currencySpcRes = ures_getByKeyWithFallback(currencyResource,
+ gCurrencySpacingTag, NULL, &localStatus);
+
+ if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
+ const char* keywords[UNUM_CURRENCY_SPACING_COUNT] = {
+ gCurrencyMatchTag, gCurrencySudMatchTag, gCurrencyInsertBtnTag
+ };
+ localStatus = U_ZERO_ERROR;
+ UResourceBundle *dataRes = ures_getByKeyWithFallback(currencySpcRes,
+ gBeforeCurrencyTag, NULL, &localStatus);
+ if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
+ localStatus = U_ZERO_ERROR;
+ for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) {
+ currencySpcBeforeSym[i] = ures_getStringByKey(dataRes, keywords[i],
+ NULL, &localStatus);
+ }
+ ures_close(dataRes);
+ }
+ dataRes = ures_getByKeyWithFallback(currencySpcRes,
+ gAfterCurrencyTag, NULL, &localStatus);
+ if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
+ localStatus = U_ZERO_ERROR;
+ for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) {
+ currencySpcAfterSym[i] = ures_getStringByKey(dataRes, keywords[i],
+ NULL, &localStatus);
+ }
+ ures_close(dataRes);
+ }
+ ures_close(currencySpcRes);
+ ures_close(currencyResource);
+ }
+ }
+ ures_close(resource);
+ ures_close(numberElementsRes);
+
+}
+
+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[kOneDigitSymbol] = (UChar)0x31; // '1' native 1 digit
+ fSymbols[kTwoDigitSymbol] = (UChar)0x32; // '2' native 2 digit
+ fSymbols[kThreeDigitSymbol] = (UChar)0x33; // '3' native 3 digit
+ fSymbols[kFourDigitSymbol] = (UChar)0x34; // '4' native 4 digit
+ fSymbols[kFiveDigitSymbol] = (UChar)0x35; // '5' native 5 digit
+ fSymbols[kSixDigitSymbol] = (UChar)0x36; // '6' native 6 digit
+ fSymbols[kSevenDigitSymbol] = (UChar)0x37; // '7' native 7 digit
+ fSymbols[kEightDigitSymbol] = (UChar)0x38; // '8' native 8 digit
+ fSymbols[kNineDigitSymbol] = (UChar)0x39; // '9' native 9 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
+ fSymbols[kMonetaryGroupingSeparatorSymbol].remove(); //
+}
+
+Locale
+DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocale(type, status);
+}
+
+const UnicodeString&
+DecimalFormatSymbols::getPatternForCurrencySpacing(UCurrencySpacing type,
+ UBool beforeCurrency,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return fNoSymbol; // always empty.
+ }
+ if (beforeCurrency) {
+ return currencySpcBeforeSym[(int32_t)type];
+ } else {
+ return currencySpcAfterSym[(int32_t)type];
+ }
+}
+
+void
+DecimalFormatSymbols::setPatternForCurrencySpacing(UCurrencySpacing type,
+ UBool beforeCurrency,
+ const UnicodeString& pattern) {
+ if (beforeCurrency) {
+ currencySpcBeforeSym[(int32_t)type] = pattern;
+ } else {
+ currencySpcAfterSym[(int32_t)type] = pattern;
+ }
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decContext.c b/Build/source/libs/icu/icu-4.8.1/i18n/decContext.c
new file mode 100644
index 00000000000..513e0215971
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decContext.c
@@ -0,0 +1,435 @@
+/* ------------------------------------------------------------------ */
+/* Decimal Context module */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2010. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+/* This module comprises the routines for handling arithmetic */
+/* context structures. */
+/* ------------------------------------------------------------------ */
+
+#include <string.h> /* for strcmp */
+#include <stdio.h> /* for printf if DECCHECK */
+#include "decContext.h" /* context and base types */
+#include "decNumberLocal.h" /* decNumber local types, etc. */
+
+/* compile-time endian tester [assumes sizeof(Int)>1] */
+static const Int mfcone=1; /* constant 1 */
+static const Flag *mfctop=(Flag *)&mfcone; /* -> top byte */
+#define LITEND *mfctop /* named flag; 1=little-endian */
+
+/* ------------------------------------------------------------------ */
+/* round-for-reround digits */
+/* ------------------------------------------------------------------ */
+const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */
+
+/* ------------------------------------------------------------------ */
+/* Powers of ten (powers[n]==10**n, 0<=n<=9) */
+/* ------------------------------------------------------------------ */
+const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000,
+ 10000000, 100000000, 1000000000};
+
+/* ------------------------------------------------------------------ */
+/* decContextClearStatus -- clear bits in current status */
+/* */
+/* context is the context structure to be queried */
+/* mask indicates the bits to be cleared (the status bit that */
+/* corresponds to each 1 bit in the mask is cleared) */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *context, uInt mask) {
+ context->status&=~mask;
+ return context;
+ } /* decContextClearStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextDefault -- initialize a context structure */
+/* */
+/* context is the structure to be initialized */
+/* kind selects the required set of default values, one of: */
+/* DEC_INIT_BASE -- select ANSI X3-274 defaults */
+/* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */
+/* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */
+/* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */
+/* For any other value a valid context is returned, but with */
+/* Invalid_operation set in the status field. */
+/* returns a context structure with the appropriate initial values. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextDefault(decContext *context, Int kind) {
+ /* set defaults... */
+ context->digits=9; /* 9 digits */
+ context->emax=DEC_MAX_EMAX; /* 9-digit exponents */
+ context->emin=DEC_MIN_EMIN; /* .. balanced */
+ context->round=DEC_ROUND_HALF_UP; /* 0.5 rises */
+ context->traps=DEC_Errors; /* all but informational */
+ context->status=0; /* cleared */
+ context->clamp=0; /* no clamping */
+ #if DECSUBSET
+ context->extended=0; /* cleared */
+ #endif
+ switch (kind) {
+ case DEC_INIT_BASE:
+ /* [use defaults] */
+ break;
+ case DEC_INIT_DECIMAL32:
+ context->digits=7; /* digits */
+ context->emax=96; /* Emax */
+ context->emin=-95; /* Emin */
+ context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
+ context->traps=0; /* no traps set */
+ context->clamp=1; /* clamp exponents */
+ #if DECSUBSET
+ context->extended=1; /* set */
+ #endif
+ break;
+ case DEC_INIT_DECIMAL64:
+ context->digits=16; /* digits */
+ context->emax=384; /* Emax */
+ context->emin=-383; /* Emin */
+ context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
+ context->traps=0; /* no traps set */
+ context->clamp=1; /* clamp exponents */
+ #if DECSUBSET
+ context->extended=1; /* set */
+ #endif
+ break;
+ case DEC_INIT_DECIMAL128:
+ context->digits=34; /* digits */
+ context->emax=6144; /* Emax */
+ context->emin=-6143; /* Emin */
+ context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
+ context->traps=0; /* no traps set */
+ context->clamp=1; /* clamp exponents */
+ #if DECSUBSET
+ context->extended=1; /* set */
+ #endif
+ break;
+
+ default: /* invalid Kind */
+ /* use defaults, and .. */
+ uprv_decContextSetStatus(context, DEC_Invalid_operation); /* trap */
+ }
+
+ return context;} /* decContextDefault */
+
+/* ------------------------------------------------------------------ */
+/* decContextGetRounding -- return current rounding mode */
+/* */
+/* context is the context structure to be queried */
+/* returns the rounding mode */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI enum rounding U_EXPORT2 uprv_decContextGetRounding(decContext *context) {
+ return context->round;
+ } /* decContextGetRounding */
+
+/* ------------------------------------------------------------------ */
+/* decContextGetStatus -- return current status */
+/* */
+/* context is the context structure to be queried */
+/* returns status */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextGetStatus(decContext *context) {
+ return context->status;
+ } /* decContextGetStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextRestoreStatus -- restore bits in current status */
+/* */
+/* context is the context structure to be updated */
+/* newstatus is the source for the bits to be restored */
+/* mask indicates the bits to be restored (the status bit that */
+/* corresponds to each 1 bit in the mask is set to the value of */
+/* the correspnding bit in newstatus) */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *context,
+ uInt newstatus, uInt mask) {
+ context->status&=~mask; /* clear the selected bits */
+ context->status|=(mask&newstatus); /* or in the new bits */
+ return context;
+ } /* decContextRestoreStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextSaveStatus -- save bits in current status */
+/* */
+/* context is the context structure to be queried */
+/* mask indicates the bits to be saved (the status bits that */
+/* correspond to each 1 bit in the mask are saved) */
+/* returns the AND of the mask and the current status */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextSaveStatus(decContext *context, uInt mask) {
+ return context->status&mask;
+ } /* decContextSaveStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetRounding -- set current rounding mode */
+/* */
+/* context is the context structure to be updated */
+/* newround is the value which will replace the current mode */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *context,
+ enum rounding newround) {
+ context->round=newround;
+ return context;
+ } /* decContextSetRounding */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatus -- set status and raise trap if appropriate */
+/* */
+/* context is the context structure to be updated */
+/* status is the DEC_ exception code */
+/* returns the context structure */
+/* */
+/* Control may never return from this routine, if there is a signal */
+/* handler and it takes a long jump. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatus(decContext *context, uInt status) {
+ context->status|=status;
+ if (status & context->traps) raise(SIGFPE);
+ return context;} /* decContextSetStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatusFromString -- set status from a string + trap */
+/* */
+/* context is the context structure to be updated */
+/* string is a string exactly equal to one that might be returned */
+/* by decContextStatusToString */
+/* */
+/* The status bit corresponding to the string is set, and a trap */
+/* is raised if appropriate. */
+/* */
+/* returns the context structure, unless the string is equal to */
+/* DEC_Condition_MU or is not recognized. In these cases NULL is */
+/* returned. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromString(decContext *context,
+ const char *string) {
+ if (strcmp(string, DEC_Condition_CS)==0)
+ return uprv_decContextSetStatus(context, DEC_Conversion_syntax);
+ if (strcmp(string, DEC_Condition_DZ)==0)
+ return uprv_decContextSetStatus(context, DEC_Division_by_zero);
+ if (strcmp(string, DEC_Condition_DI)==0)
+ return uprv_decContextSetStatus(context, DEC_Division_impossible);
+ if (strcmp(string, DEC_Condition_DU)==0)
+ return uprv_decContextSetStatus(context, DEC_Division_undefined);
+ if (strcmp(string, DEC_Condition_IE)==0)
+ return uprv_decContextSetStatus(context, DEC_Inexact);
+ if (strcmp(string, DEC_Condition_IS)==0)
+ return uprv_decContextSetStatus(context, DEC_Insufficient_storage);
+ if (strcmp(string, DEC_Condition_IC)==0)
+ return uprv_decContextSetStatus(context, DEC_Invalid_context);
+ if (strcmp(string, DEC_Condition_IO)==0)
+ return uprv_decContextSetStatus(context, DEC_Invalid_operation);
+ #if DECSUBSET
+ if (strcmp(string, DEC_Condition_LD)==0)
+ return uprv_decContextSetStatus(context, DEC_Lost_digits);
+ #endif
+ if (strcmp(string, DEC_Condition_OV)==0)
+ return uprv_decContextSetStatus(context, DEC_Overflow);
+ if (strcmp(string, DEC_Condition_PA)==0)
+ return uprv_decContextSetStatus(context, DEC_Clamped);
+ if (strcmp(string, DEC_Condition_RO)==0)
+ return uprv_decContextSetStatus(context, DEC_Rounded);
+ if (strcmp(string, DEC_Condition_SU)==0)
+ return uprv_decContextSetStatus(context, DEC_Subnormal);
+ if (strcmp(string, DEC_Condition_UN)==0)
+ return uprv_decContextSetStatus(context, DEC_Underflow);
+ if (strcmp(string, DEC_Condition_ZE)==0)
+ return context;
+ return NULL; /* Multiple status, or unknown */
+ } /* decContextSetStatusFromString */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatusFromStringQuiet -- set status from a string */
+/* */
+/* context is the context structure to be updated */
+/* string is a string exactly equal to one that might be returned */
+/* by decContextStatusToString */
+/* */
+/* The status bit corresponding to the string is set; no trap is */
+/* raised. */
+/* */
+/* returns the context structure, unless the string is equal to */
+/* DEC_Condition_MU or is not recognized. In these cases NULL is */
+/* returned. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *context,
+ const char *string) {
+ if (strcmp(string, DEC_Condition_CS)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Conversion_syntax);
+ if (strcmp(string, DEC_Condition_DZ)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Division_by_zero);
+ if (strcmp(string, DEC_Condition_DI)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Division_impossible);
+ if (strcmp(string, DEC_Condition_DU)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Division_undefined);
+ if (strcmp(string, DEC_Condition_IE)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Inexact);
+ if (strcmp(string, DEC_Condition_IS)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Insufficient_storage);
+ if (strcmp(string, DEC_Condition_IC)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Invalid_context);
+ if (strcmp(string, DEC_Condition_IO)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Invalid_operation);
+ #if DECSUBSET
+ if (strcmp(string, DEC_Condition_LD)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Lost_digits);
+ #endif
+ if (strcmp(string, DEC_Condition_OV)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Overflow);
+ if (strcmp(string, DEC_Condition_PA)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Clamped);
+ if (strcmp(string, DEC_Condition_RO)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Rounded);
+ if (strcmp(string, DEC_Condition_SU)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Subnormal);
+ if (strcmp(string, DEC_Condition_UN)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Underflow);
+ if (strcmp(string, DEC_Condition_ZE)==0)
+ return context;
+ return NULL; /* Multiple status, or unknown */
+ } /* decContextSetStatusFromStringQuiet */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatusQuiet -- set status without trap */
+/* */
+/* context is the context structure to be updated */
+/* status is the DEC_ exception code */
+/* returns the context structure */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
+ context->status|=status;
+ return context;} /* decContextSetStatusQuiet */
+
+/* ------------------------------------------------------------------ */
+/* decContextStatusToString -- convert status flags to a string */
+/* */
+/* context is a context with valid status field */
+/* */
+/* returns a constant string describing the condition. If multiple */
+/* (or no) flags are set, a generic constant message is returned. */
+/* ------------------------------------------------------------------ */
+U_CAPI const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *context) {
+ Int status=context->status;
+
+ /* test the five IEEE first, as some of the others are ambiguous when */
+ /* DECEXTFLAG=0 */
+ if (status==DEC_Invalid_operation ) return DEC_Condition_IO;
+ if (status==DEC_Division_by_zero ) return DEC_Condition_DZ;
+ if (status==DEC_Overflow ) return DEC_Condition_OV;
+ if (status==DEC_Underflow ) return DEC_Condition_UN;
+ if (status==DEC_Inexact ) return DEC_Condition_IE;
+
+ if (status==DEC_Division_impossible ) return DEC_Condition_DI;
+ if (status==DEC_Division_undefined ) return DEC_Condition_DU;
+ if (status==DEC_Rounded ) return DEC_Condition_RO;
+ if (status==DEC_Clamped ) return DEC_Condition_PA;
+ if (status==DEC_Subnormal ) return DEC_Condition_SU;
+ if (status==DEC_Conversion_syntax ) return DEC_Condition_CS;
+ if (status==DEC_Insufficient_storage ) return DEC_Condition_IS;
+ if (status==DEC_Invalid_context ) return DEC_Condition_IC;
+ #if DECSUBSET
+ if (status==DEC_Lost_digits ) return DEC_Condition_LD;
+ #endif
+ if (status==0 ) return DEC_Condition_ZE;
+ return DEC_Condition_MU; /* Multiple errors */
+ } /* decContextStatusToString */
+
+/* ------------------------------------------------------------------ */
+/* decContextTestEndian -- test whether DECLITEND is set correctly */
+/* */
+/* quiet is 1 to suppress message; 0 otherwise */
+/* returns 0 if DECLITEND is correct */
+/* 1 if DECLITEND is incorrect and should be 1 */
+/* -1 if DECLITEND is incorrect and should be 0 */
+/* */
+/* A message is displayed if the return value is not 0 and quiet==0. */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI Int U_EXPORT2 uprv_decContextTestEndian(Flag quiet) {
+ Int res=0; /* optimist */
+ uInt dle=(uInt)DECLITEND; /* unsign */
+ if (dle>1) dle=1; /* ensure 0 or 1 */
+
+ if (LITEND!=DECLITEND) {
+ const char *adj;
+ if (!quiet) {
+ if (LITEND) adj="little";
+ else adj="big";
+ printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n",
+ DECLITEND, adj);
+ }
+ res=(Int)LITEND-dle;
+ }
+ return res;
+ } /* decContextTestEndian */
+
+/* ------------------------------------------------------------------ */
+/* decContextTestSavedStatus -- test bits in saved status */
+/* */
+/* oldstatus is the status word to be tested */
+/* mask indicates the bits to be tested (the oldstatus bits that */
+/* correspond to each 1 bit in the mask are tested) */
+/* returns 1 if any of the tested bits are 1, or 0 otherwise */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
+ return (oldstatus&mask)!=0;
+ } /* decContextTestSavedStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextTestStatus -- test bits in current status */
+/* */
+/* context is the context structure to be updated */
+/* mask indicates the bits to be tested (the status bits that */
+/* correspond to each 1 bit in the mask are tested) */
+/* returns 1 if any of the tested bits are 1, or 0 otherwise */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextTestStatus(decContext *context, uInt mask) {
+ return (context->status&mask)!=0;
+ } /* decContextTestStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextZeroStatus -- clear all status bits */
+/* */
+/* context is the context structure to be updated */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) {
+ context->status=0;
+ return context;
+ } /* decContextZeroStatus */
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decContext.h b/Build/source/libs/icu/icu-4.8.1/i18n/decContext.h
new file mode 100644
index 00000000000..c25e495e76f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decContext.h
@@ -0,0 +1,267 @@
+/* ------------------------------------------------------------------ */
+/* Decimal Context module header */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2010. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+
+/* Modified version, for use from within ICU.
+ * Renamed public functions, to avoid an unwanted export of the
+ * standard names from the ICU library.
+ *
+ * Use ICU's uprv_malloc() and uprv_free()
+ *
+ * Revert comment syntax to plain C
+ *
+ * Remove a few compiler warnings.
+ */
+#include "unicode/utypes.h"
+
+/* */
+/* Context variables must always have valid values: */
+/* */
+/* status -- [any bits may be cleared, but not set, by user] */
+/* round -- must be one of the enumerated rounding modes */
+/* */
+/* The following variables are implied for fixed size formats (i.e., */
+/* they are ignored) but should still be set correctly in case used */
+/* with decNumber functions: */
+/* */
+/* clamp -- must be either 0 or 1 */
+/* digits -- must be in the range 1 through 999999999 */
+/* emax -- must be in the range 0 through 999999999 */
+/* emin -- must be in the range 0 through -999999999 */
+/* extended -- must be either 0 or 1 [present only if DECSUBSET] */
+/* traps -- only defined bits may be set */
+/* */
+/* ------------------------------------------------------------------ */
+
+#if !defined(DECCONTEXT)
+ #define DECCONTEXT
+ #define DECCNAME "decContext" /* Short name */
+ #define DECCFULLNAME "Decimal Context Descriptor" /* Verbose name */
+ #define DECCAUTHOR "Mike Cowlishaw" /* Who to blame */
+
+ #if !defined(int32_t)
+/* #include <stdint.h> */ /* C99 standard integers */
+ #endif
+ #include <stdio.h> /* for printf, etc. */
+ #include <signal.h> /* for traps */
+
+ /* Extended flags setting -- set this to 0 to use only IEEE flags */
+ #if !defined(DECEXTFLAG)
+ #define DECEXTFLAG 1 /* 1=enable extended flags */
+ #endif
+
+ /* Conditional code flag -- set this to 0 for best performance */
+ #if !defined(DECSUBSET)
+ #define DECSUBSET 0 /* 1=enable subset arithmetic */
+ #endif
+
+ /* Context for operations, with associated constants */
+ enum rounding {
+ DEC_ROUND_CEILING, /* round towards +infinity */
+ DEC_ROUND_UP, /* round away from 0 */
+ DEC_ROUND_HALF_UP, /* 0.5 rounds up */
+ DEC_ROUND_HALF_EVEN, /* 0.5 rounds to nearest even */
+ DEC_ROUND_HALF_DOWN, /* 0.5 rounds down */
+ DEC_ROUND_DOWN, /* round towards 0 (truncate) */
+ DEC_ROUND_FLOOR, /* round towards -infinity */
+ DEC_ROUND_05UP, /* round for reround */
+ DEC_ROUND_MAX /* enum must be less than this */
+ };
+ #define DEC_ROUND_DEFAULT DEC_ROUND_HALF_EVEN;
+
+ typedef struct {
+ int32_t digits; /* working precision */
+ int32_t emax; /* maximum positive exponent */
+ int32_t emin; /* minimum negative exponent */
+ enum rounding round; /* rounding mode */
+ uint32_t traps; /* trap-enabler flags */
+ uint32_t status; /* status flags */
+ uint8_t clamp; /* flag: apply IEEE exponent clamp */
+ #if DECSUBSET
+ uint8_t extended; /* flag: special-values allowed */
+ #endif
+ } decContext;
+
+ /* Maxima and Minima for context settings */
+ #define DEC_MAX_DIGITS 999999999
+ #define DEC_MIN_DIGITS 1
+ #define DEC_MAX_EMAX 999999999
+ #define DEC_MIN_EMAX 0
+ #define DEC_MAX_EMIN 0
+ #define DEC_MIN_EMIN -999999999
+ #define DEC_MAX_MATH 999999 /* max emax, etc., for math funcs. */
+
+ /* Classifications for decimal numbers, aligned with 754 (note that */
+ /* 'normal' and 'subnormal' are meaningful only with a decContext */
+ /* or a fixed size format). */
+ enum decClass {
+ DEC_CLASS_SNAN,
+ DEC_CLASS_QNAN,
+ DEC_CLASS_NEG_INF,
+ DEC_CLASS_NEG_NORMAL,
+ DEC_CLASS_NEG_SUBNORMAL,
+ DEC_CLASS_NEG_ZERO,
+ DEC_CLASS_POS_ZERO,
+ DEC_CLASS_POS_SUBNORMAL,
+ DEC_CLASS_POS_NORMAL,
+ DEC_CLASS_POS_INF
+ };
+ /* Strings for the decClasses */
+ #define DEC_ClassString_SN "sNaN"
+ #define DEC_ClassString_QN "NaN"
+ #define DEC_ClassString_NI "-Infinity"
+ #define DEC_ClassString_NN "-Normal"
+ #define DEC_ClassString_NS "-Subnormal"
+ #define DEC_ClassString_NZ "-Zero"
+ #define DEC_ClassString_PZ "+Zero"
+ #define DEC_ClassString_PS "+Subnormal"
+ #define DEC_ClassString_PN "+Normal"
+ #define DEC_ClassString_PI "+Infinity"
+ #define DEC_ClassString_UN "Invalid"
+
+ /* Trap-enabler and Status flags (exceptional conditions), and */
+ /* their names. The top byte is reserved for internal use */
+ #if DECEXTFLAG
+ /* Extended flags */
+ #define DEC_Conversion_syntax 0x00000001
+ #define DEC_Division_by_zero 0x00000002
+ #define DEC_Division_impossible 0x00000004
+ #define DEC_Division_undefined 0x00000008
+ #define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */
+ #define DEC_Inexact 0x00000020
+ #define DEC_Invalid_context 0x00000040
+ #define DEC_Invalid_operation 0x00000080
+ #if DECSUBSET
+ #define DEC_Lost_digits 0x00000100
+ #endif
+ #define DEC_Overflow 0x00000200
+ #define DEC_Clamped 0x00000400
+ #define DEC_Rounded 0x00000800
+ #define DEC_Subnormal 0x00001000
+ #define DEC_Underflow 0x00002000
+ #else
+ /* IEEE flags only */
+ #define DEC_Conversion_syntax 0x00000010
+ #define DEC_Division_by_zero 0x00000002
+ #define DEC_Division_impossible 0x00000010
+ #define DEC_Division_undefined 0x00000010
+ #define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */
+ #define DEC_Inexact 0x00000001
+ #define DEC_Invalid_context 0x00000010
+ #define DEC_Invalid_operation 0x00000010
+ #if DECSUBSET
+ #define DEC_Lost_digits 0x00000000
+ #endif
+ #define DEC_Overflow 0x00000008
+ #define DEC_Clamped 0x00000000
+ #define DEC_Rounded 0x00000000
+ #define DEC_Subnormal 0x00000000
+ #define DEC_Underflow 0x00000004
+ #endif
+
+ /* IEEE 754 groupings for the flags */
+ /* [DEC_Clamped, DEC_Lost_digits, DEC_Rounded, and DEC_Subnormal */
+ /* are not in IEEE 754] */
+ #define DEC_IEEE_754_Division_by_zero (DEC_Division_by_zero)
+ #if DECSUBSET
+ #define DEC_IEEE_754_Inexact (DEC_Inexact | DEC_Lost_digits)
+ #else
+ #define DEC_IEEE_754_Inexact (DEC_Inexact)
+ #endif
+ #define DEC_IEEE_754_Invalid_operation (DEC_Conversion_syntax | \
+ DEC_Division_impossible | \
+ DEC_Division_undefined | \
+ DEC_Insufficient_storage | \
+ DEC_Invalid_context | \
+ DEC_Invalid_operation)
+ #define DEC_IEEE_754_Overflow (DEC_Overflow)
+ #define DEC_IEEE_754_Underflow (DEC_Underflow)
+
+ /* flags which are normally errors (result is qNaN, infinite, or 0) */
+ #define DEC_Errors (DEC_IEEE_754_Division_by_zero | \
+ DEC_IEEE_754_Invalid_operation | \
+ DEC_IEEE_754_Overflow | DEC_IEEE_754_Underflow)
+ /* flags which cause a result to become qNaN */
+ #define DEC_NaNs DEC_IEEE_754_Invalid_operation
+
+ /* flags which are normally for information only (finite results) */
+ #if DECSUBSET
+ #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact \
+ | DEC_Lost_digits)
+ #else
+ #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact)
+ #endif
+
+ /* IEEE 854 names (for compatibility with older decNumber versions) */
+ #define DEC_IEEE_854_Division_by_zero DEC_IEEE_754_Division_by_zero
+ #define DEC_IEEE_854_Inexact DEC_IEEE_754_Inexact
+ #define DEC_IEEE_854_Invalid_operation DEC_IEEE_754_Invalid_operation
+ #define DEC_IEEE_854_Overflow DEC_IEEE_754_Overflow
+ #define DEC_IEEE_854_Underflow DEC_IEEE_754_Underflow
+
+ /* Name strings for the exceptional conditions */
+ #define DEC_Condition_CS "Conversion syntax"
+ #define DEC_Condition_DZ "Division by zero"
+ #define DEC_Condition_DI "Division impossible"
+ #define DEC_Condition_DU "Division undefined"
+ #define DEC_Condition_IE "Inexact"
+ #define DEC_Condition_IS "Insufficient storage"
+ #define DEC_Condition_IC "Invalid context"
+ #define DEC_Condition_IO "Invalid operation"
+ #if DECSUBSET
+ #define DEC_Condition_LD "Lost digits"
+ #endif
+ #define DEC_Condition_OV "Overflow"
+ #define DEC_Condition_PA "Clamped"
+ #define DEC_Condition_RO "Rounded"
+ #define DEC_Condition_SU "Subnormal"
+ #define DEC_Condition_UN "Underflow"
+ #define DEC_Condition_ZE "No status"
+ #define DEC_Condition_MU "Multiple status"
+ #define DEC_Condition_Length 21 /* length of the longest string, */
+ /* including terminator */
+
+ /* Initialization descriptors, used by decContextDefault */
+ #define DEC_INIT_BASE 0
+ #define DEC_INIT_DECIMAL32 32
+ #define DEC_INIT_DECIMAL64 64
+ #define DEC_INIT_DECIMAL128 128
+ /* Synonyms */
+ #define DEC_INIT_DECSINGLE DEC_INIT_DECIMAL32
+ #define DEC_INIT_DECDOUBLE DEC_INIT_DECIMAL64
+ #define DEC_INIT_DECQUAD DEC_INIT_DECIMAL128
+
+ /* decContext routines */
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *, uint32_t);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextDefault(decContext *, int32_t);
+ U_INTERNAL enum rounding U_EXPORT2 uprv_decContextGetRounding(decContext *);
+ U_INTERNAL uint32_t U_EXPORT2 uprv_decContextGetStatus(decContext *);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *, uint32_t, uint32_t);
+ U_INTERNAL uint32_t U_EXPORT2 uprv_decContextSaveStatus(decContext *, uint32_t);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *, enum rounding);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatus(decContext *, uint32_t);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatusFromString(decContext *, const char *);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *, const char *);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *, uint32_t);
+ U_INTERNAL const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *);
+ U_INTERNAL int32_t U_EXPORT2 uprv_decContextTestEndian(uint8_t);
+ U_INTERNAL uint32_t U_EXPORT2 uprv_decContextTestSavedStatus(uint32_t, uint32_t);
+ U_INTERNAL uint32_t U_EXPORT2 uprv_decContextTestStatus(decContext *, uint32_t);
+ U_INTERNAL decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *);
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decNumber.c b/Build/source/libs/icu/icu-4.8.1/i18n/decNumber.c
new file mode 100644
index 00000000000..ab690782f32
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decNumber.c
@@ -0,0 +1,8143 @@
+/* ------------------------------------------------------------------ */
+/* Decimal Number arithmetic module */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2010. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+
+/* Modified version, for use from within ICU.
+ * Renamed public functions, to avoid an unwanted export of the
+ * standard names from the ICU library.
+ *
+ * Use ICU's uprv_malloc() and uprv_free()
+ *
+ * Revert comment syntax to plain C
+ *
+ * Remove a few compiler warnings.
+ */
+
+/* This module comprises the routines for arbitrary-precision General */
+/* Decimal Arithmetic as defined in the specification which may be */
+/* found on the General Decimal Arithmetic pages. It implements both */
+/* the full ('extended') arithmetic and the simpler ('subset') */
+/* arithmetic. */
+/* */
+/* Usage notes: */
+/* */
+/* 1. This code is ANSI C89 except: */
+/* */
+/* a) C99 line comments (double forward slash) are used. (Most C */
+/* compilers accept these. If yours does not, a simple script */
+/* can be used to convert them to ANSI C comments.) */
+/* */
+/* b) Types from C99 stdint.h are used. If you do not have this */
+/* header file, see the User's Guide section of the decNumber */
+/* documentation; this lists the necessary definitions. */
+/* */
+/* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */
+/* uint64_t types may be used. To avoid these, set DECUSE64=0 */
+/* and DECDPUN<=4 (see documentation). */
+/* */
+/* The code also conforms to C99 restrictions; in particular, */
+/* strict aliasing rules are observed. */
+/* */
+/* 2. The decNumber format which this library uses is optimized for */
+/* efficient processing of relatively short numbers; in particular */
+/* it allows the use of fixed sized structures and minimizes copy */
+/* and move operations. It does, however, support arbitrary */
+/* precision (up to 999,999,999 digits) and arbitrary exponent */
+/* range (Emax in the range 0 through 999,999,999 and Emin in the */
+/* range -999,999,999 through 0). Mathematical functions (for */
+/* example decNumberExp) as identified below are restricted more */
+/* tightly: digits, emax, and -emin in the context must be <= */
+/* DEC_MAX_MATH (999999), and their operand(s) must be within */
+/* these bounds. */
+/* */
+/* 3. Logical functions are further restricted; their operands must */
+/* be finite, positive, have an exponent of zero, and all digits */
+/* must be either 0 or 1. The result will only contain digits */
+/* which are 0 or 1 (and will have exponent=0 and a sign of 0). */
+/* */
+/* 4. Operands to operator functions are never modified unless they */
+/* are also specified to be the result number (which is always */
+/* permitted). Other than that case, operands must not overlap. */
+/* */
+/* 5. Error handling: the type of the error is ORed into the status */
+/* flags in the current context (decContext structure). The */
+/* SIGFPE signal is then raised if the corresponding trap-enabler */
+/* flag in the decContext is set (is 1). */
+/* */
+/* It is the responsibility of the caller to clear the status */
+/* flags as required. */
+/* */
+/* The result of any routine which returns a number will always */
+/* be a valid number (which may be a special value, such as an */
+/* Infinity or NaN). */
+/* */
+/* 6. The decNumber format is not an exchangeable concrete */
+/* representation as it comprises fields which may be machine- */
+/* dependent (packed or unpacked, or special length, for example). */
+/* Canonical conversions to and from strings are provided; other */
+/* conversions are available in separate modules. */
+/* */
+/* 7. Normally, input operands are assumed to be valid. Set DECCHECK */
+/* to 1 for extended operand checking (including NULL operands). */
+/* Results are undefined if a badly-formed structure (or a NULL */
+/* pointer to a structure) is provided, though with DECCHECK */
+/* enabled the operator routines are protected against exceptions. */
+/* (Except if the result pointer is NULL, which is unrecoverable.) */
+/* */
+/* However, the routines will never cause exceptions if they are */
+/* given well-formed operands, even if the value of the operands */
+/* is inappropriate for the operation and DECCHECK is not set. */
+/* (Except for SIGFPE, as and where documented.) */
+/* */
+/* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */
+/* ------------------------------------------------------------------ */
+/* Implementation notes for maintenance of this module: */
+/* */
+/* 1. Storage leak protection: Routines which use malloc are not */
+/* permitted to use return for fastpath or error exits (i.e., */
+/* they follow strict structured programming conventions). */
+/* Instead they have a do{}while(0); construct surrounding the */
+/* code which is protected -- break may be used to exit this. */
+/* Other routines can safely use the return statement inline. */
+/* */
+/* Storage leak accounting can be enabled using DECALLOC. */
+/* */
+/* 2. All loops use the for(;;) construct. Any do construct does */
+/* not loop; it is for allocation protection as just described. */
+/* */
+/* 3. Setting status in the context must always be the very last */
+/* action in a routine, as non-0 status may raise a trap and hence */
+/* the call to set status may not return (if the handler uses long */
+/* jump). Therefore all cleanup must be done first. In general, */
+/* to achieve this status is accumulated and is only applied just */
+/* before return by calling decContextSetStatus (via decStatus). */
+/* */
+/* Routines which allocate storage cannot, in general, use the */
+/* 'top level' routines which could cause a non-returning */
+/* transfer of control. The decXxxxOp routines are safe (do not */
+/* call decStatus even if traps are set in the context) and should */
+/* be used instead (they are also a little faster). */
+/* */
+/* 4. Exponent checking is minimized by allowing the exponent to */
+/* grow outside its limits during calculations, provided that */
+/* the decFinalize function is called later. Multiplication and */
+/* division, and intermediate calculations in exponentiation, */
+/* require more careful checks because of the risk of 31-bit */
+/* overflow (the most negative valid exponent is -1999999997, for */
+/* a 999999999-digit number with adjusted exponent of -999999999). */
+/* */
+/* 5. Rounding is deferred until finalization of results, with any */
+/* 'off to the right' data being represented as a single digit */
+/* residue (in the range -1 through 9). This avoids any double- */
+/* rounding when more than one shortening takes place (for */
+/* example, when a result is subnormal). */
+/* */
+/* 6. The digits count is allowed to rise to a multiple of DECDPUN */
+/* during many operations, so whole Units are handled and exact */
+/* accounting of digits is not needed. The correct digits value */
+/* is found by decGetDigits, which accounts for leading zeros. */
+/* This must be called before any rounding if the number of digits */
+/* is not known exactly. */
+/* */
+/* 7. The multiply-by-reciprocal 'trick' is used for partitioning */
+/* numbers up to four digits, using appropriate constants. This */
+/* is not useful for longer numbers because overflow of 32 bits */
+/* would lead to 4 multiplies, which is almost as expensive as */
+/* a divide (unless a floating-point or 64-bit multiply is */
+/* assumed to be available). */
+/* */
+/* 8. Unusual abbreviations that may be used in the commentary: */
+/* lhs -- left hand side (operand, of an operation) */
+/* lsd -- least significant digit (of coefficient) */
+/* lsu -- least significant Unit (of coefficient) */
+/* msd -- most significant digit (of coefficient) */
+/* msi -- most significant item (in an array) */
+/* msu -- most significant Unit (of coefficient) */
+/* rhs -- right hand side (operand, of an operation) */
+/* +ve -- positive */
+/* -ve -- negative */
+/* ** -- raise to the power */
+/* ------------------------------------------------------------------ */
+
+#include <stdlib.h> /* for malloc, free, etc. */
+/* #include <stdio.h> */ /* for printf [if needed] */
+#include <string.h> /* for strcpy */
+#include <ctype.h> /* for lower */
+#include "cmemory.h" /* for uprv_malloc, etc., in ICU */
+#include "decNumber.h" /* base number library */
+#include "decNumberLocal.h" /* decNumber local types, etc. */
+
+/* Constants */
+/* Public lookup table used by the D2U macro */
+const uByte d2utable[DECMAXD2U+1]=D2UTABLE;
+
+#define DECVERB 1 /* set to 1 for verbose DECCHECK */
+#define powers DECPOWERS /* old internal name */
+
+/* Local constants */
+#define DIVIDE 0x80 /* Divide operators */
+#define REMAINDER 0x40 /* .. */
+#define DIVIDEINT 0x20 /* .. */
+#define REMNEAR 0x10 /* .. */
+#define COMPARE 0x01 /* Compare operators */
+#define COMPMAX 0x02 /* .. */
+#define COMPMIN 0x03 /* .. */
+#define COMPTOTAL 0x04 /* .. */
+#define COMPNAN 0x05 /* .. [NaN processing] */
+#define COMPSIG 0x06 /* .. [signaling COMPARE] */
+#define COMPMAXMAG 0x07 /* .. */
+#define COMPMINMAG 0x08 /* .. */
+
+#define DEC_sNaN 0x40000000 /* local status: sNaN signal */
+#define BADINT (Int)0x80000000 /* most-negative Int; error indicator */
+/* Next two indicate an integer >= 10**6, and its parity (bottom bit) */
+#define BIGEVEN (Int)0x80000002
+#define BIGODD (Int)0x80000003
+
+static Unit uarrone[1]={1}; /* Unit array of 1, used for incrementing */
+
+/* Granularity-dependent code */
+#if DECDPUN<=4
+ #define eInt Int /* extended integer */
+ #define ueInt uInt /* unsigned extended integer */
+ /* Constant multipliers for divide-by-power-of five using reciprocal */
+ /* multiply, after removing powers of 2 by shifting, and final shift */
+ /* of 17 [we only need up to **4] */
+ static const uInt multies[]={131073, 26215, 5243, 1049, 210};
+ /* QUOT10 -- macro to return the quotient of unit u divided by 10**n */
+ #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
+#else
+ /* For DECDPUN>4 non-ANSI-89 64-bit types are needed. */
+ #if !DECUSE64
+ #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4
+ #endif
+ #define eInt Long /* extended integer */
+ #define ueInt uLong /* unsigned extended integer */
+#endif
+
+/* Local routines */
+static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *,
+ decContext *, uByte, uInt *);
+static Flag decBiStr(const char *, const char *, const char *);
+static uInt decCheckMath(const decNumber *, decContext *, uInt *);
+static void decApplyRound(decNumber *, decContext *, Int, uInt *);
+static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag);
+static decNumber * decCompareOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *,
+ Flag, uInt *);
+static void decCopyFit(decNumber *, const decNumber *, decContext *,
+ Int *, uInt *);
+static decNumber * decDecap(decNumber *, Int);
+static decNumber * decDivideOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *, Flag, uInt *);
+static decNumber * decExpOp(decNumber *, const decNumber *,
+ decContext *, uInt *);
+static void decFinalize(decNumber *, decContext *, Int *, uInt *);
+static Int decGetDigits(Unit *, Int);
+static Int decGetInt(const decNumber *);
+static decNumber * decLnOp(decNumber *, const decNumber *,
+ decContext *, uInt *);
+static decNumber * decMultiplyOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *,
+ uInt *);
+static decNumber * decNaNs(decNumber *, const decNumber *,
+ const decNumber *, decContext *, uInt *);
+static decNumber * decQuantizeOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *, Flag,
+ uInt *);
+static void decReverse(Unit *, Unit *);
+static void decSetCoeff(decNumber *, decContext *, const Unit *,
+ Int, Int *, uInt *);
+static void decSetMaxValue(decNumber *, decContext *);
+static void decSetOverflow(decNumber *, decContext *, uInt *);
+static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *);
+static Int decShiftToLeast(Unit *, Int, Int);
+static Int decShiftToMost(Unit *, Int, Int);
+static void decStatus(decNumber *, uInt, decContext *);
+static void decToString(const decNumber *, char[], Flag);
+static decNumber * decTrim(decNumber *, decContext *, Flag, Flag, Int *);
+static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int,
+ Unit *, Int);
+static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int);
+
+#if !DECSUBSET
+/* decFinish == decFinalize when no subset arithmetic needed */
+#define decFinish(a,b,c,d) decFinalize(a,b,c,d)
+#else
+static void decFinish(decNumber *, decContext *, Int *, uInt *);
+static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *);
+#endif
+
+/* Local macros */
+/* masked special-values bits */
+#define SPECIALARG (rhs->bits & DECSPECIAL)
+#define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL)
+
+/* For use in ICU */
+#define malloc(a) uprv_malloc(a)
+#define free(a) uprv_free(a)
+
+/* Diagnostic macros, etc. */
+#if DECALLOC
+/* Handle malloc/free accounting. If enabled, our accountable routines */
+/* are used; otherwise the code just goes straight to the system malloc */
+/* and free routines. */
+#define malloc(a) decMalloc(a)
+#define free(a) decFree(a)
+#define DECFENCE 0x5a /* corruption detector */
+/* 'Our' malloc and free: */
+static void *decMalloc(size_t);
+static void decFree(void *);
+uInt decAllocBytes=0; /* count of bytes allocated */
+/* Note that DECALLOC code only checks for storage buffer overflow. */
+/* To check for memory leaks, the decAllocBytes variable must be */
+/* checked to be 0 at appropriate times (e.g., after the test */
+/* harness completes a set of tests). This checking may be unreliable */
+/* if the testing is done in a multi-thread environment. */
+#endif
+
+#if DECCHECK
+/* Optional checking routines. Enabling these means that decNumber */
+/* and decContext operands to operator routines are checked for */
+/* correctness. This roughly doubles the execution time of the */
+/* fastest routines (and adds 600+ bytes), so should not normally be */
+/* used in 'production'. */
+/* decCheckInexact is used to check that inexact results have a full */
+/* complement of digits (where appropriate -- this is not the case */
+/* for Quantize, for example) */
+#define DECUNRESU ((decNumber *)(void *)0xffffffff)
+#define DECUNUSED ((const decNumber *)(void *)0xffffffff)
+#define DECUNCONT ((decContext *)(void *)(0xffffffff))
+static Flag decCheckOperands(decNumber *, const decNumber *,
+ const decNumber *, decContext *);
+static Flag decCheckNumber(const decNumber *);
+static void decCheckInexact(const decNumber *, decContext *);
+#endif
+
+#if DECTRACE || DECCHECK
+/* Optional trace/debugging routines (may or may not be used) */
+void decNumberShow(const decNumber *); /* displays the components of a number */
+static void decDumpAr(char, const Unit *, Int);
+#endif
+
+/* ================================================================== */
+/* Conversions */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* from-int32 -- conversion from Int or uInt */
+/* */
+/* dn is the decNumber to receive the integer */
+/* in or uin is the integer to be converted */
+/* returns dn */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *dn, Int in) {
+ uInt unsig;
+ if (in>=0) unsig=in;
+ else { /* negative (possibly BADINT) */
+ if (in==BADINT) unsig=(uInt)1073741824*2; /* special case */
+ else unsig=-in; /* invert */
+ }
+ /* in is now positive */
+ uprv_decNumberFromUInt32(dn, unsig);
+ if (in<0) dn->bits=DECNEG; /* sign needed */
+ return dn;
+ } /* decNumberFromInt32 */
+
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
+ Unit *up; /* work pointer */
+ uprv_decNumberZero(dn); /* clean */
+ if (uin==0) return dn; /* [or decGetDigits bad call] */
+ for (up=dn->lsu; uin>0; up++) {
+ *up=(Unit)(uin%(DECDPUNMAX+1));
+ uin=uin/(DECDPUNMAX+1);
+ }
+ dn->digits=decGetDigits(dn->lsu, up-dn->lsu);
+ return dn;
+ } /* decNumberFromUInt32 */
+
+/* ------------------------------------------------------------------ */
+/* to-int32 -- conversion to Int or uInt */
+/* */
+/* dn is the decNumber to convert */
+/* set is the context for reporting errors */
+/* returns the converted decNumber, or 0 if Invalid is set */
+/* */
+/* Invalid is set if the decNumber does not have exponent==0 or if */
+/* it is a NaN, Infinite, or out-of-range. */
+/* ------------------------------------------------------------------ */
+U_CAPI Int U_EXPORT2 uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+
+ /* special or too many digits, or bad exponent */
+ if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; /* bad */
+ else { /* is a finite integer with 10 or fewer digits */
+ Int d; /* work */
+ const Unit *up; /* .. */
+ uInt hi=0, lo; /* .. */
+ up=dn->lsu; /* -> lsu */
+ lo=*up; /* get 1 to 9 digits */
+ #if DECDPUN>1 /* split to higher */
+ hi=lo/10;
+ lo=lo%10;
+ #endif
+ up++;
+ /* collect remaining Units, if any, into hi */
+ for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
+ /* now low has the lsd, hi the remainder */
+ if (hi>214748364 || (hi==214748364 && lo>7)) { /* out of range? */
+ /* most-negative is a reprieve */
+ if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000;
+ /* bad -- drop through */
+ }
+ else { /* in-range always */
+ Int i=X10(hi)+lo;
+ if (dn->bits&DECNEG) return -i;
+ return i;
+ }
+ } /* integer */
+ uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
+ return 0;
+ } /* decNumberToInt32 */
+
+U_CAPI uInt U_EXPORT2 uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+ /* special or too many digits, or bad exponent, or negative (<0) */
+ if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0
+ || (dn->bits&DECNEG && !ISZERO(dn))); /* bad */
+ else { /* is a finite integer with 10 or fewer digits */
+ Int d; /* work */
+ const Unit *up; /* .. */
+ uInt hi=0, lo; /* .. */
+ up=dn->lsu; /* -> lsu */
+ lo=*up; /* get 1 to 9 digits */
+ #if DECDPUN>1 /* split to higher */
+ hi=lo/10;
+ lo=lo%10;
+ #endif
+ up++;
+ /* collect remaining Units, if any, into hi */
+ for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
+
+ /* now low has the lsd, hi the remainder */
+ if (hi>429496729 || (hi==429496729 && lo>5)) ; /* no reprieve possible */
+ else return X10(hi)+lo;
+ } /* integer */
+ uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
+ return 0;
+ } /* decNumberToUInt32 */
+
+/* ------------------------------------------------------------------ */
+/* to-scientific-string -- conversion to numeric string */
+/* to-engineering-string -- conversion to numeric string */
+/* */
+/* decNumberToString(dn, string); */
+/* decNumberToEngString(dn, string); */
+/* */
+/* dn is the decNumber to convert */
+/* string is the string where the result will be laid out */
+/* */
+/* string must be at least dn->digits+14 characters long */
+/* */
+/* No error is possible, and no status can be set. */
+/* ------------------------------------------------------------------ */
+U_CAPI char * U_EXPORT2 uprv_decNumberToString(const decNumber *dn, char *string){
+ decToString(dn, string, 0);
+ return string;
+ } /* DecNumberToString */
+
+U_CAPI char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *dn, char *string){
+ decToString(dn, string, 1);
+ return string;
+ } /* DecNumberToEngString */
+
+/* ------------------------------------------------------------------ */
+/* to-number -- conversion from numeric string */
+/* */
+/* decNumberFromString -- convert string to decNumber */
+/* dn -- the number structure to fill */
+/* chars[] -- the string to convert ('\0' terminated) */
+/* set -- the context used for processing any error, */
+/* determining the maximum precision available */
+/* (set.digits), determining the maximum and minimum */
+/* exponent (set.emax and set.emin), determining if */
+/* extended values are allowed, and checking the */
+/* rounding mode if overflow occurs or rounding is */
+/* needed. */
+/* */
+/* The length of the coefficient and the size of the exponent are */
+/* checked by this routine, so the correct error (Underflow or */
+/* Overflow) can be reported or rounding applied, as necessary. */
+/* */
+/* If bad syntax is detected, the result will be a quiet NaN. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *dn, const char chars[],
+ decContext *set) {
+ Int exponent=0; /* working exponent [assume 0] */
+ uByte bits=0; /* working flags [assume +ve] */
+ Unit *res; /* where result will be built */
+ Unit resbuff[SD2U(DECBUFFER+9)];/* local buffer in case need temporary */
+ /* [+9 allows for ln() constants] */
+ Unit *allocres=NULL; /* -> allocated result, iff allocated */
+ Int d=0; /* count of digits found in decimal part */
+ const char *dotchar=NULL; /* where dot was found */
+ const char *cfirst=chars; /* -> first character of decimal part */
+ const char *last=NULL; /* -> last digit of decimal part */
+ const char *c; /* work */
+ Unit *up; /* .. */
+ #if DECDPUN>1
+ Int cut, out; /* .. */
+ #endif
+ Int residue; /* rounding residue */
+ uInt status=0; /* error code */
+
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set))
+ return uprv_decNumberZero(dn);
+ #endif
+
+ do { /* status & malloc protection */
+ for (c=chars;; c++) { /* -> input character */
+ if (*c>='0' && *c<='9') { /* test for Arabic digit */
+ last=c;
+ d++; /* count of real digits */
+ continue; /* still in decimal part */
+ }
+ if (*c=='.' && dotchar==NULL) { /* first '.' */
+ dotchar=c; /* record offset into decimal part */
+ if (c==cfirst) cfirst++; /* first digit must follow */
+ continue;}
+ if (c==chars) { /* first in string... */
+ if (*c=='-') { /* valid - sign */
+ cfirst++;
+ bits=DECNEG;
+ continue;}
+ if (*c=='+') { /* valid + sign */
+ cfirst++;
+ continue;}
+ }
+ /* *c is not a digit, or a valid +, -, or '.' */
+ break;
+ } /* c */
+
+ if (last==NULL) { /* no digits yet */
+ status=DEC_Conversion_syntax;/* assume the worst */
+ if (*c=='\0') break; /* and no more to come... */
+ #if DECSUBSET
+ /* if subset then infinities and NaNs are not allowed */
+ if (!set->extended) break; /* hopeless */
+ #endif
+ /* Infinities and NaNs are possible, here */
+ if (dotchar!=NULL) break; /* .. unless had a dot */
+ uprv_decNumberZero(dn); /* be optimistic */
+ if (decBiStr(c, "infinity", "INFINITY")
+ || decBiStr(c, "inf", "INF")) {
+ dn->bits=bits | DECINF;
+ status=0; /* is OK */
+ break; /* all done */
+ }
+ /* a NaN expected */
+ /* 2003.09.10 NaNs are now permitted to have a sign */
+ dn->bits=bits | DECNAN; /* assume simple NaN */
+ if (*c=='s' || *c=='S') { /* looks like an sNaN */
+ c++;
+ dn->bits=bits | DECSNAN;
+ }
+ if (*c!='n' && *c!='N') break; /* check caseless "NaN" */
+ c++;
+ if (*c!='a' && *c!='A') break; /* .. */
+ c++;
+ if (*c!='n' && *c!='N') break; /* .. */
+ c++;
+ /* now either nothing, or nnnn payload, expected */
+ /* -> start of integer and skip leading 0s [including plain 0] */
+ for (cfirst=c; *cfirst=='0';) cfirst++;
+ if (*cfirst=='\0') { /* "NaN" or "sNaN", maybe with all 0s */
+ status=0; /* it's good */
+ break; /* .. */
+ }
+ /* something other than 0s; setup last and d as usual [no dots] */
+ for (c=cfirst;; c++, d++) {
+ if (*c<'0' || *c>'9') break; /* test for Arabic digit */
+ last=c;
+ }
+ if (*c!='\0') break; /* not all digits */
+ if (d>set->digits-1) {
+ /* [NB: payload in a decNumber can be full length unless */
+ /* clamped, in which case can only be digits-1] */
+ if (set->clamp) break;
+ if (d>set->digits) break;
+ } /* too many digits? */
+ /* good; drop through to convert the integer to coefficient */
+ status=0; /* syntax is OK */
+ bits=dn->bits; /* for copy-back */
+ } /* last==NULL */
+
+ else if (*c!='\0') { /* more to process... */
+ /* had some digits; exponent is only valid sequence now */
+ Flag nege; /* 1=negative exponent */
+ const char *firstexp; /* -> first significant exponent digit */
+ status=DEC_Conversion_syntax;/* assume the worst */
+ if (*c!='e' && *c!='E') break;
+ /* Found 'e' or 'E' -- now process explicit exponent */
+ /* 1998.07.11: sign no longer required */
+ nege=0;
+ c++; /* to (possible) sign */
+ if (*c=='-') {nege=1; c++;}
+ else if (*c=='+') c++;
+ if (*c=='\0') break;
+
+ for (; *c=='0' && *(c+1)!='\0';) c++; /* strip insignificant zeros */
+ firstexp=c; /* save exponent digit place */
+ for (; ;c++) {
+ if (*c<'0' || *c>'9') break; /* not a digit */
+ exponent=X10(exponent)+(Int)*c-(Int)'0';
+ } /* c */
+ /* if not now on a '\0', *c must not be a digit */
+ if (*c!='\0') break;
+
+ /* (this next test must be after the syntax checks) */
+ /* if it was too long the exponent may have wrapped, so check */
+ /* carefully and set it to a certain overflow if wrap possible */
+ if (c>=firstexp+9+1) {
+ if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2;
+ /* [up to 1999999999 is OK, for example 1E-1000000998] */
+ }
+ if (nege) exponent=-exponent; /* was negative */
+ status=0; /* is OK */
+ } /* stuff after digits */
+
+ /* Here when whole string has been inspected; syntax is good */
+ /* cfirst->first digit (never dot), last->last digit (ditto) */
+
+ /* strip leading zeros/dot [leave final 0 if all 0's] */
+ if (*cfirst=='0') { /* [cfirst has stepped over .] */
+ for (c=cfirst; c<last; c++, cfirst++) {
+ if (*c=='.') continue; /* ignore dots */
+ if (*c!='0') break; /* non-zero found */
+ d--; /* 0 stripped */
+ } /* c */
+ #if DECSUBSET
+ /* make a rapid exit for easy zeros if !extended */
+ if (*cfirst=='0' && !set->extended) {
+ uprv_decNumberZero(dn); /* clean result */
+ break; /* [could be return] */
+ }
+ #endif
+ } /* at least one leading 0 */
+
+ /* Handle decimal point... */
+ if (dotchar!=NULL && dotchar<last) /* non-trailing '.' found? */
+ exponent-=(last-dotchar); /* adjust exponent */
+ /* [we can now ignore the .] */
+
+ /* OK, the digits string is good. Assemble in the decNumber, or in */
+ /* a temporary units array if rounding is needed */
+ if (d<=set->digits) res=dn->lsu; /* fits into supplied decNumber */
+ else { /* rounding needed */
+ Int needbytes=D2U(d)*sizeof(Unit);/* bytes needed */
+ res=resbuff; /* assume use local buffer */
+ if (needbytes>(Int)sizeof(resbuff)) { /* too big for local */
+ allocres=(Unit *)malloc(needbytes);
+ if (allocres==NULL) {status|=DEC_Insufficient_storage; break;}
+ res=allocres;
+ }
+ }
+ /* res now -> number lsu, buffer, or allocated storage for Unit array */
+
+ /* Place the coefficient into the selected Unit array */
+ /* [this is often 70% of the cost of this function when DECDPUN>1] */
+ #if DECDPUN>1
+ out=0; /* accumulator */
+ up=res+D2U(d)-1; /* -> msu */
+ cut=d-(up-res)*DECDPUN; /* digits in top unit */
+ for (c=cfirst;; c++) { /* along the digits */
+ if (*c=='.') continue; /* ignore '.' [don't decrement cut] */
+ out=X10(out)+(Int)*c-(Int)'0';
+ if (c==last) break; /* done [never get to trailing '.'] */
+ cut--;
+ if (cut>0) continue; /* more for this unit */
+ *up=(Unit)out; /* write unit */
+ up--; /* prepare for unit below.. */
+ cut=DECDPUN; /* .. */
+ out=0; /* .. */
+ } /* c */
+ *up=(Unit)out; /* write lsu */
+
+ #else
+ /* DECDPUN==1 */
+ up=res; /* -> lsu */
+ for (c=last; c>=cfirst; c--) { /* over each character, from least */
+ if (*c=='.') continue; /* ignore . [don't step up] */
+ *up=(Unit)((Int)*c-(Int)'0');
+ up++;
+ } /* c */
+ #endif
+
+ dn->bits=bits;
+ dn->exponent=exponent;
+ dn->digits=d;
+
+ /* if not in number (too long) shorten into the number */
+ if (d>set->digits) {
+ residue=0;
+ decSetCoeff(dn, set, res, d, &residue, &status);
+ /* always check for overflow or subnormal and round as needed */
+ decFinalize(dn, set, &residue, &status);
+ }
+ else { /* no rounding, but may still have overflow or subnormal */
+ /* [these tests are just for performance; finalize repeats them] */
+ if ((dn->exponent-1<set->emin-dn->digits)
+ || (dn->exponent-1>set->emax-set->digits)) {
+ residue=0;
+ decFinalize(dn, set, &residue, &status);
+ }
+ }
+ /* decNumberShow(dn); */
+ } while(0); /* [for break] */
+
+ if (allocres!=NULL) free(allocres); /* drop any storage used */
+ if (status!=0) decStatus(dn, status, set);
+ return dn;
+ } /* decNumberFromString */
+
+/* ================================================================== */
+/* Operators */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* decNumberAbs -- absolute value operator */
+/* */
+/* This computes C = abs(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* See also decNumberCopyAbs for a quiet bitwise version of this. */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This has the same effect as decNumberPlus unless A is negative, */
+/* in which case it has the same effect as decNumberMinus. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dzero; /* for 0 */
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ uprv_decNumberZero(&dzero); /* set 0 */
+ dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
+ decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberAbs */
+
+/* ------------------------------------------------------------------ */
+/* decNumberAdd -- add two Numbers */
+/* */
+/* This computes C = A + B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This just calls the routine shared with Subtract */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decAddOp(res, lhs, rhs, set, 0, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberAdd */
+
+/* ------------------------------------------------------------------ */
+/* decNumberAnd -- AND two Numbers, digitwise */
+/* */
+/* This computes C = A & B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X&X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ const Unit *ua, *ub; /* -> operands */
+ const Unit *msua, *msub; /* -> operand msus */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
+ || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+
+ /* operands are valid */
+ ua=lhs->lsu; /* bottom-up */
+ ub=rhs->lsu; /* .. */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
+ msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
+ Unit a, b; /* extract units */
+ if (ua>msua) a=0;
+ else a=*ua;
+ if (ub>msub) b=0;
+ else b=*ub;
+ *uc=0; /* can now write back */
+ if (a|b) { /* maybe 1 bits to examine */
+ Int i, j;
+ *uc=0; /* can now write back */
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if (a&b&1) *uc=*uc+(Unit)powers[i]; /* effect AND */
+ j=a%10;
+ a=a/10;
+ j|=b%10;
+ b=b/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* both OK */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, uc-res->lsu);
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberAnd */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompare -- compare two Numbers */
+/* */
+/* This computes C = A ? B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit (or NaN). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPARE, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompare */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompareSignal -- compare, signalling on all NaNs */
+/* */
+/* This computes C = A ? B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit (or NaN). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPSIG, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompareSignal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompareTotal -- compare two Numbers, using total ordering */
+/* */
+/* This computes C = A ? B, under total ordering */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit; the result will always be one of */
+/* -1, 0, or 1. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompareTotal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompareTotalMag -- compare, total ordering of magnitudes */
+/* */
+/* This computes C = |A| ? |B|, under total ordering */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit; the result will always be one of */
+/* -1, 0, or 1. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ uInt needbytes; /* for space calculations */
+ decNumber bufa[D2N(DECBUFFER+1)];/* +1 in case DECBUFFER=0 */
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber bufb[D2N(DECBUFFER+1)];
+ decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
+ decNumber *a, *b; /* temporary pointers */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ /* if either is negative, take a copy and absolute */
+ if (decNumberIsNegative(lhs)) { /* lhs<0 */
+ a=bufa;
+ needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ uprv_decNumberCopy(a, lhs); /* copy content */
+ a->bits&=~DECNEG; /* .. and clear the sign */
+ lhs=a; /* use copy from here on */
+ }
+ if (decNumberIsNegative(rhs)) { /* rhs<0 */
+ b=bufb;
+ needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufb)) { /* need malloc space */
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufb==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ b=allocbufb; /* use the allocated space */
+ }
+ uprv_decNumberCopy(b, rhs); /* copy content */
+ b->bits&=~DECNEG; /* .. and clear the sign */
+ rhs=b; /* use copy from here on */
+ }
+ decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
+ } while(0); /* end protected */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompareTotalMag */
+
+/* ------------------------------------------------------------------ */
+/* decNumberDivide -- divide one number by another */
+/* */
+/* This computes C = A / B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X/X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, DIVIDE, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberDivide */
+
+/* ------------------------------------------------------------------ */
+/* decNumberDivideInteger -- divide and return integer quotient */
+/* */
+/* This computes C = A # B, where # is the integer divide operator */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X#X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberDivideInteger */
+
+/* ------------------------------------------------------------------ */
+/* decNumberExp -- exponentiation */
+/* */
+/* This computes C = exp(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* Finite results will always be full precision and Inexact, except */
+/* when A is a zero or -Infinity (giving 1 or 0 respectively). */
+/* */
+/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* This is a wrapper for decExpOp which can handle the slightly wider */
+/* (double) range needed by Ln (which has to be able to calculate */
+/* exp(-a) where a can be the tiniest number (Ntiny). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* Check restrictions; these restrictions ensure that if h=8 (see */
+ /* decExpOp) then the result will either overflow or underflow to 0. */
+ /* Other math functions restrict the input range, too, for inverses. */
+ /* If not violated then carry out the operation. */
+ if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ decExpOp(res, rhs, set, &status);
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
+ #endif
+ /* apply significant status */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberExp */
+
+/* ------------------------------------------------------------------ */
+/* decNumberFMA -- fused multiply add */
+/* */
+/* This computes D = (A * B) + C with only one rounding */
+/* */
+/* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */
+/* lhs is A */
+/* rhs is B */
+/* fhs is C [far hand side] */
+/* set is the context */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, const decNumber *fhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+ decContext dcmul; /* context for the multiplication */
+ uInt needbytes; /* for space calculations */
+ decNumber bufa[D2N(DECBUFFER*2+1)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *acc; /* accumulator pointer */
+ decNumber dzero; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ if (decCheckOperands(res, fhs, DECUNUSED, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) { /* [undefined if subset] */
+ status|=DEC_Invalid_operation;
+ break;}
+ #endif
+ /* Check math restrictions [these ensure no overflow or underflow] */
+ if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status))
+ || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status))
+ || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break;
+ /* set up context for multiply */
+ dcmul=*set;
+ dcmul.digits=lhs->digits+rhs->digits; /* just enough */
+ /* [The above may be an over-estimate for subset arithmetic, but that's OK] */
+ dcmul.emax=DEC_MAX_EMAX; /* effectively unbounded .. */
+ dcmul.emin=DEC_MIN_EMIN; /* [thanks to Math restrictions] */
+ /* set up decNumber space to receive the result of the multiply */
+ acc=bufa; /* may fit */
+ needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ acc=allocbufa; /* use the allocated space */
+ }
+ /* multiply with extended range and necessary precision */
+ /*printf("emin=%ld\n", dcmul.emin); */
+ decMultiplyOp(acc, lhs, rhs, &dcmul, &status);
+ /* Only Invalid operation (from sNaN or Inf * 0) is possible in */
+ /* status; if either is seen than ignore fhs (in case it is */
+ /* another sNaN) and set acc to NaN unless we had an sNaN */
+ /* [decMultiplyOp leaves that to caller] */
+ /* Note sNaN has to go through addOp to shorten payload if */
+ /* necessary */
+ if ((status&DEC_Invalid_operation)!=0) {
+ if (!(status&DEC_sNaN)) { /* but be true invalid */
+ uprv_decNumberZero(res); /* acc not yet set */
+ res->bits=DECNAN;
+ break;
+ }
+ uprv_decNumberZero(&dzero); /* make 0 (any non-NaN would do) */
+ fhs=&dzero; /* use that */
+ }
+ #if DECCHECK
+ else { /* multiply was OK */
+ if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status);
+ }
+ #endif
+ /* add the third operand and result -> res, and all is done */
+ decAddOp(res, acc, fhs, set, 0, &status);
+ } while(0); /* end protected */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberFMA */
+
+/* ------------------------------------------------------------------ */
+/* decNumberInvert -- invert a Number, digitwise */
+/* */
+/* This computes C = ~A */
+/* */
+/* res is C, the result. C may be A (e.g., X=~X) */
+/* rhs is A */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ const Unit *ua, *msua; /* -> operand and its msu */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ /* operand is valid */
+ ua=rhs->lsu; /* bottom-up */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, uc++) { /* Unit loop */
+ Unit a; /* extract unit */
+ Int i, j; /* work */
+ if (ua>msua) a=0;
+ else a=*ua;
+ *uc=0; /* can now write back */
+ /* always need to examine all bits in rhs */
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if ((~a)&1) *uc=*uc+(Unit)powers[i]; /* effect INVERT */
+ j=a%10;
+ a=a/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, uc-res->lsu);
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberInvert */
+
+/* ------------------------------------------------------------------ */
+/* decNumberLn -- natural logarithm */
+/* */
+/* This computes C = ln(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Notable cases: */
+/* A<0 -> Invalid */
+/* A=0 -> -Infinity (Exact) */
+/* A=+Infinity -> +Infinity (Exact) */
+/* A=1 exactly -> 0 (Exact) */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* This is a wrapper for decLnOp which can handle the slightly wider */
+/* (+11) range needed by Ln, Log10, etc. (which may have to be able */
+/* to calculate at p+e+2). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberLn(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* Check restrictions; this is a math function; if not violated */
+ /* then carry out the operation. */
+ if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ /* special check in subset for rhs=0 */
+ if (ISZERO(rhs)) { /* +/- zeros -> error */
+ status|=DEC_Invalid_operation;
+ break;}
+ } /* extended=0 */
+ #endif
+ decLnOp(res, rhs, set, &status);
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
+ #endif
+ /* apply significant status */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberLn */
+
+/* ------------------------------------------------------------------ */
+/* decNumberLogB - get adjusted exponent, by 754 rules */
+/* */
+/* This computes C = adjustedexponent(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context, used only for digits and status */
+/* */
+/* C must have space for 10 digits (A might have 10**9 digits and */
+/* an exponent of +999999999, or one digit and an exponent of */
+/* -1999999999). */
+/* */
+/* This returns the adjusted exponent of A after (in theory) padding */
+/* with zeros on the right to set->digits digits while keeping the */
+/* same value. The exponent is not limited by emin/emax. */
+/* */
+/* Notable cases: */
+/* A<0 -> Use |A| */
+/* A=0 -> -Infinity (Division by zero) */
+/* A=Infinite -> +Infinity (Exact) */
+/* A=1 exactly -> 0 (Exact) */
+/* NaNs are propagated as usual */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberLogB(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* NaNs as usual; Infinities return +Infinity; 0->oops */
+ if (decNumberIsNaN(rhs)) decNaNs(res, rhs, NULL, set, &status);
+ else if (decNumberIsInfinite(rhs)) uprv_decNumberCopyAbs(res, rhs);
+ else if (decNumberIsZero(rhs)) {
+ uprv_decNumberZero(res); /* prepare for Infinity */
+ res->bits=DECNEG|DECINF; /* -Infinity */
+ status|=DEC_Division_by_zero; /* as per 754 */
+ }
+ else { /* finite non-zero */
+ Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
+ uprv_decNumberFromInt32(res, ae); /* lay it out */
+ }
+
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberLogB */
+
+/* ------------------------------------------------------------------ */
+/* decNumberLog10 -- logarithm in base 10 */
+/* */
+/* This computes C = log10(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Notable cases: */
+/* A<0 -> Invalid */
+/* A=0 -> -Infinity (Exact) */
+/* A=+Infinity -> +Infinity (Exact) */
+/* A=10**n (if n is an integer) -> n (Exact) */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* This calculates ln(A)/ln(10) using appropriate precision. For */
+/* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */
+/* requested digits and t is the number of digits in the exponent */
+/* (maximum 6). For ln(10) it is p + 3; this is often handled by the */
+/* fastpath in decLnOp. The final division is done to the requested */
+/* precision. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberLog10(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0, ignore=0; /* status accumulators */
+ uInt needbytes; /* for space calculations */
+ Int p; /* working precision */
+ Int t; /* digits in exponent of A */
+
+ /* buffers for a and b working decimals */
+ /* (adjustment calculator, same size) */
+ decNumber bufa[D2N(DECBUFFER+2)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *a=bufa; /* temporary a */
+ decNumber bufb[D2N(DECBUFFER+2)];
+ decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
+ decNumber *b=bufb; /* temporary b */
+ decNumber bufw[D2N(10)]; /* working 2-10 digit number */
+ decNumber *w=bufw; /* .. */
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+
+ decContext aset; /* working context */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* Check restrictions; this is a math function; if not violated */
+ /* then carry out the operation. */
+ if (!decCheckMath(rhs, set, &status)) do { /* protect malloc */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ /* special check in subset for rhs=0 */
+ if (ISZERO(rhs)) { /* +/- zeros -> error */
+ status|=DEC_Invalid_operation;
+ break;}
+ } /* extended=0 */
+ #endif
+
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
+
+ /* handle exact powers of 10; only check if +ve finite */
+ if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) {
+ Int residue=0; /* (no residue) */
+ uInt copystat=0; /* clean status */
+
+ /* round to a single digit... */
+ aset.digits=1;
+ decCopyFit(w, rhs, &aset, &residue, &copystat); /* copy & shorten */
+ /* if exact and the digit is 1, rhs is a power of 10 */
+ if (!(copystat&DEC_Inexact) && w->lsu[0]==1) {
+ /* the exponent, conveniently, is the power of 10; making */
+ /* this the result needs a little care as it might not fit, */
+ /* so first convert it into the working number, and then move */
+ /* to res */
+ uprv_decNumberFromInt32(w, w->exponent);
+ residue=0;
+ decCopyFit(res, w, set, &residue, &status); /* copy & round */
+ decFinish(res, set, &residue, &status); /* cleanup/set flags */
+ break;
+ } /* not a power of 10 */
+ } /* not a candidate for exact */
+
+ /* simplify the information-content calculation to use 'total */
+ /* number of digits in a, including exponent' as compared to the */
+ /* requested digits, as increasing this will only rarely cost an */
+ /* iteration in ln(a) anyway */
+ t=6; /* it can never be >6 */
+
+ /* allocate space when needed... */
+ p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3;
+ needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ aset.digits=p; /* as calculated */
+ aset.emax=DEC_MAX_MATH; /* usual bounds */
+ aset.emin=-DEC_MAX_MATH; /* .. */
+ aset.clamp=0; /* and no concrete format */
+ decLnOp(a, rhs, &aset, &status); /* a=ln(rhs) */
+
+ /* skip the division if the result so far is infinite, NaN, or */
+ /* zero, or there was an error; note NaN from sNaN needs copy */
+ if (status&DEC_NaNs && !(status&DEC_sNaN)) break;
+ if (a->bits&DECSPECIAL || ISZERO(a)) {
+ uprv_decNumberCopy(res, a); /* [will fit] */
+ break;}
+
+ /* for ln(10) an extra 3 digits of precision are needed */
+ p=set->digits+3;
+ needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufb)) { /* need malloc space */
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufb==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ b=allocbufb; /* use the allocated space */
+ }
+ uprv_decNumberZero(w); /* set up 10... */
+ #if DECDPUN==1
+ w->lsu[1]=1; w->lsu[0]=0; /* .. */
+ #else
+ w->lsu[0]=10; /* .. */
+ #endif
+ w->digits=2; /* .. */
+
+ aset.digits=p;
+ decLnOp(b, w, &aset, &ignore); /* b=ln(10) */
+
+ aset.digits=set->digits; /* for final divide */
+ decDivideOp(res, a, b, &aset, DIVIDE, &status); /* into result */
+ } while(0); /* [for break] */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* .. */
+ #endif
+ /* apply significant status */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberLog10 */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMax -- compare two Numbers and return the maximum */
+/* */
+/* This computes C = A ? B, returning the maximum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMax(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMAX, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMax */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMaxMag -- compare and return the maximum by magnitude */
+/* */
+/* This computes C = A ? B, returning the maximum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMaxMag(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMaxMag */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMin -- compare two Numbers and return the minimum */
+/* */
+/* This computes C = A ? B, returning the minimum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMin(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMIN, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMin */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMinMag -- compare and return the minimum by magnitude */
+/* */
+/* This computes C = A ? B, returning the minimum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinMag(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMinMag */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMinus -- prefix minus operator */
+/* */
+/* This computes C = 0 - A */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* See also decNumberCopyNegate for a quiet bitwise version of this. */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* Simply use AddOp for the subtract, which will do the necessary. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dzero;
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ uprv_decNumberZero(&dzero); /* make 0 */
+ dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
+ decAddOp(res, &dzero, rhs, set, DECNEG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMinus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberNextMinus -- next towards -Infinity */
+/* */
+/* This computes C = A - infinitesimal, rounded towards -Infinity */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* This is a generalization of 754 NextDown. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextMinus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dtiny; /* constant */
+ decContext workset=*set; /* work */
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* +Infinity is the special case */
+ if ((rhs->bits&(DECINF|DECNEG))==DECINF) {
+ decSetMaxValue(res, set); /* is +ve */
+ /* there is no status to set */
+ return res;
+ }
+ uprv_decNumberZero(&dtiny); /* start with 0 */
+ dtiny.lsu[0]=1; /* make number that is .. */
+ dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
+ workset.round=DEC_ROUND_FLOOR;
+ decAddOp(res, rhs, &dtiny, &workset, DECNEG, &status);
+ status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberNextMinus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberNextPlus -- next towards +Infinity */
+/* */
+/* This computes C = A + infinitesimal, rounded towards +Infinity */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* This is a generalization of 754 NextUp. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextPlus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dtiny; /* constant */
+ decContext workset=*set; /* work */
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* -Infinity is the special case */
+ if ((rhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
+ decSetMaxValue(res, set);
+ res->bits=DECNEG; /* negative */
+ /* there is no status to set */
+ return res;
+ }
+ uprv_decNumberZero(&dtiny); /* start with 0 */
+ dtiny.lsu[0]=1; /* make number that is .. */
+ dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
+ workset.round=DEC_ROUND_CEILING;
+ decAddOp(res, rhs, &dtiny, &workset, 0, &status);
+ status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberNextPlus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberNextToward -- next towards rhs */
+/* */
+/* This computes C = A +/- infinitesimal, rounded towards */
+/* +/-Infinity in the direction of B, as per 754-1985 nextafter */
+/* modified during revision but dropped from 754-2008. */
+/* */
+/* res is C, the result. C may be A or B. */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* This is a generalization of 754-1985 NextAfter. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextToward(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ decNumber dtiny; /* constant */
+ decContext workset=*set; /* work */
+ Int result; /* .. */
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) {
+ decNaNs(res, lhs, rhs, set, &status);
+ }
+ else { /* Is numeric, so no chance of sNaN Invalid, etc. */
+ result=decCompare(lhs, rhs, 0); /* sign matters */
+ if (result==BADINT) status|=DEC_Insufficient_storage; /* rare */
+ else { /* valid compare */
+ if (result==0) uprv_decNumberCopySign(res, lhs, rhs); /* easy */
+ else { /* differ: need NextPlus or NextMinus */
+ uByte sub; /* add or subtract */
+ if (result<0) { /* lhs<rhs, do nextplus */
+ /* -Infinity is the special case */
+ if ((lhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
+ decSetMaxValue(res, set);
+ res->bits=DECNEG; /* negative */
+ return res; /* there is no status to set */
+ }
+ workset.round=DEC_ROUND_CEILING;
+ sub=0; /* add, please */
+ } /* plus */
+ else { /* lhs>rhs, do nextminus */
+ /* +Infinity is the special case */
+ if ((lhs->bits&(DECINF|DECNEG))==DECINF) {
+ decSetMaxValue(res, set);
+ return res; /* there is no status to set */
+ }
+ workset.round=DEC_ROUND_FLOOR;
+ sub=DECNEG; /* subtract, please */
+ } /* minus */
+ uprv_decNumberZero(&dtiny); /* start with 0 */
+ dtiny.lsu[0]=1; /* make number that is .. */
+ dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
+ decAddOp(res, lhs, &dtiny, &workset, sub, &status); /* + or - */
+ /* turn off exceptions if the result is a normal number */
+ /* (including Nmin), otherwise let all status through */
+ if (uprv_decNumberIsNormal(res, set)) status=0;
+ } /* unequal */
+ } /* compare OK */
+ } /* numeric */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberNextToward */
+
+/* ------------------------------------------------------------------ */
+/* decNumberOr -- OR two Numbers, digitwise */
+/* */
+/* This computes C = A | B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X|X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberOr(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ const Unit *ua, *ub; /* -> operands */
+ const Unit *msua, *msub; /* -> operand msus */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
+ || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ /* operands are valid */
+ ua=lhs->lsu; /* bottom-up */
+ ub=rhs->lsu; /* .. */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
+ msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
+ Unit a, b; /* extract units */
+ if (ua>msua) a=0;
+ else a=*ua;
+ if (ub>msub) b=0;
+ else b=*ub;
+ *uc=0; /* can now write back */
+ if (a|b) { /* maybe 1 bits to examine */
+ Int i, j;
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if ((a|b)&1) *uc=*uc+(Unit)powers[i]; /* effect OR */
+ j=a%10;
+ a=a/10;
+ j|=b%10;
+ b=b/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* non-zero */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, uc-res->lsu);
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberOr */
+
+/* ------------------------------------------------------------------ */
+/* decNumberPlus -- prefix plus operator */
+/* */
+/* This computes C = 0 + A */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* See also decNumberCopy for a quiet bitwise version of this. */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This simply uses AddOp; Add will take fast path after preparing A. */
+/* Performance is a concern here, as this routine is often used to */
+/* check operands and apply rounding and overflow/underflow testing. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberPlus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dzero;
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ uprv_decNumberZero(&dzero); /* make 0 */
+ dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
+ decAddOp(res, &dzero, rhs, set, 0, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberPlus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMultiply -- multiply two Numbers */
+/* */
+/* This computes C = A x B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMultiply(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decMultiplyOp(res, lhs, rhs, set, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMultiply */
+
+/* ------------------------------------------------------------------ */
+/* decNumberPower -- raise a number to a power */
+/* */
+/* This computes C = A ** B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X**X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* However, if 1999999997<=B<=999999999 and B is an integer then the */
+/* restrictions on A and the context are relaxed to the usual bounds, */
+/* for compatibility with the earlier (integer power only) version */
+/* of this function. */
+/* */
+/* When B is an integer, the result may be exact, even if rounded. */
+/* */
+/* The final result is rounded according to the context; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberPower(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ decNumber *allocdac=NULL; /* -> allocated acc buffer, iff used */
+ decNumber *allocinv=NULL; /* -> allocated 1/x buffer, iff used */
+ Int reqdigits=set->digits; /* requested DIGITS */
+ Int n; /* rhs in binary */
+ Flag rhsint=0; /* 1 if rhs is an integer */
+ Flag useint=0; /* 1 if can use integer calculation */
+ Flag isoddint=0; /* 1 if rhs is an integer and odd */
+ Int i; /* work */
+ #if DECSUBSET
+ Int dropped; /* .. */
+ #endif
+ uInt needbytes; /* buffer size needed */
+ Flag seenbit; /* seen a bit while powering */
+ Int residue=0; /* rounding residue */
+ uInt status=0; /* accumulators */
+ uByte bits=0; /* result sign if errors */
+ decContext aset; /* working context */
+ decNumber dnOne; /* work value 1... */
+ /* local accumulator buffer [a decNumber, with digits+elength+1 digits] */
+ decNumber dacbuff[D2N(DECBUFFER+9)];
+ decNumber *dac=dacbuff; /* -> result accumulator */
+ /* same again for possible 1/lhs calculation */
+ decNumber invbuff[D2N(DECBUFFER+9)];
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) { /* reduce operands and set status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, &status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* handle NaNs and rhs Infinity (lhs infinity is harder) */
+ if (SPECIALARGS) {
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { /* NaNs */
+ decNaNs(res, lhs, rhs, set, &status);
+ break;}
+ if (decNumberIsInfinite(rhs)) { /* rhs Infinity */
+ Flag rhsneg=rhs->bits&DECNEG; /* save rhs sign */
+ if (decNumberIsNegative(lhs) /* lhs<0 */
+ && !decNumberIsZero(lhs)) /* .. */
+ status|=DEC_Invalid_operation;
+ else { /* lhs >=0 */
+ uprv_decNumberZero(&dnOne); /* set up 1 */
+ dnOne.lsu[0]=1;
+ uprv_decNumberCompare(dac, lhs, &dnOne, set); /* lhs ? 1 */
+ uprv_decNumberZero(res); /* prepare for 0/1/Infinity */
+ if (decNumberIsNegative(dac)) { /* lhs<1 */
+ if (rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
+ }
+ else if (dac->lsu[0]==0) { /* lhs=1 */
+ /* 1**Infinity is inexact, so return fully-padded 1.0000 */
+ Int shift=set->digits-1;
+ *res->lsu=1; /* was 0, make int 1 */
+ res->digits=decShiftToMost(res->lsu, 1, shift);
+ res->exponent=-shift; /* make 1.0000... */
+ status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
+ }
+ else { /* lhs>1 */
+ if (!rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
+ }
+ } /* lhs>=0 */
+ break;}
+ /* [lhs infinity drops through] */
+ } /* specials */
+
+ /* Original rhs may be an integer that fits and is in range */
+ n=decGetInt(rhs);
+ if (n!=BADINT) { /* it is an integer */
+ rhsint=1; /* record the fact for 1**n */
+ isoddint=(Flag)n&1; /* [works even if big] */
+ if (n!=BIGEVEN && n!=BIGODD) /* can use integer path? */
+ useint=1; /* looks good */
+ }
+
+ if (decNumberIsNegative(lhs) /* -x .. */
+ && isoddint) bits=DECNEG; /* .. to an odd power */
+
+ /* handle LHS infinity */
+ if (decNumberIsInfinite(lhs)) { /* [NaNs already handled] */
+ uByte rbits=rhs->bits; /* save */
+ uprv_decNumberZero(res); /* prepare */
+ if (n==0) *res->lsu=1; /* [-]Inf**0 => 1 */
+ else {
+ /* -Inf**nonint -> error */
+ if (!rhsint && decNumberIsNegative(lhs)) {
+ status|=DEC_Invalid_operation; /* -Inf**nonint is error */
+ break;}
+ if (!(rbits & DECNEG)) bits|=DECINF; /* was not a **-n */
+ /* [otherwise will be 0 or -0] */
+ res->bits=bits;
+ }
+ break;}
+
+ /* similarly handle LHS zero */
+ if (decNumberIsZero(lhs)) {
+ if (n==0) { /* 0**0 => Error */
+ #if DECSUBSET
+ if (!set->extended) { /* [unless subset] */
+ uprv_decNumberZero(res);
+ *res->lsu=1; /* return 1 */
+ break;}
+ #endif
+ status|=DEC_Invalid_operation;
+ }
+ else { /* 0**x */
+ uByte rbits=rhs->bits; /* save */
+ if (rbits & DECNEG) { /* was a 0**(-n) */
+ #if DECSUBSET
+ if (!set->extended) { /* [bad if subset] */
+ status|=DEC_Invalid_operation;
+ break;}
+ #endif
+ bits|=DECINF;
+ }
+ uprv_decNumberZero(res); /* prepare */
+ /* [otherwise will be 0 or -0] */
+ res->bits=bits;
+ }
+ break;}
+
+ /* here both lhs and rhs are finite; rhs==0 is handled in the */
+ /* integer path. Next handle the non-integer cases */
+ if (!useint) { /* non-integral rhs */
+ /* any -ve lhs is bad, as is either operand or context out of */
+ /* bounds */
+ if (decNumberIsNegative(lhs)) {
+ status|=DEC_Invalid_operation;
+ break;}
+ if (decCheckMath(lhs, set, &status)
+ || decCheckMath(rhs, set, &status)) break; /* variable status */
+
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
+ aset.emax=DEC_MAX_MATH; /* usual bounds */
+ aset.emin=-DEC_MAX_MATH; /* .. */
+ aset.clamp=0; /* and no concrete format */
+
+ /* calculate the result using exp(ln(lhs)*rhs), which can */
+ /* all be done into the accumulator, dac. The precision needed */
+ /* is enough to contain the full information in the lhs (which */
+ /* is the total digits, including exponent), or the requested */
+ /* precision, if larger, + 4; 6 is used for the exponent */
+ /* maximum length, and this is also used when it is shorter */
+ /* than the requested digits as it greatly reduces the >0.5 ulp */
+ /* cases at little cost (because Ln doubles digits each */
+ /* iteration so a few extra digits rarely causes an extra */
+ /* iteration) */
+ aset.digits=MAXI(lhs->digits, set->digits)+6+4;
+ } /* non-integer rhs */
+
+ else { /* rhs is in-range integer */
+ if (n==0) { /* x**0 = 1 */
+ /* (0**0 was handled above) */
+ uprv_decNumberZero(res); /* result=1 */
+ *res->lsu=1; /* .. */
+ break;}
+ /* rhs is a non-zero integer */
+ if (n<0) n=-n; /* use abs(n) */
+
+ aset=*set; /* clone the context */
+ aset.round=DEC_ROUND_HALF_EVEN; /* internally use balanced */
+ /* calculate the working DIGITS */
+ aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2;
+ #if DECSUBSET
+ if (!set->extended) aset.digits--; /* use classic precision */
+ #endif
+ /* it's an error if this is more than can be handled */
+ if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;}
+ } /* integer path */
+
+ /* aset.digits is the count of digits for the accumulator needed */
+ /* if accumulator is too long for local storage, then allocate */
+ needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit);
+ /* [needbytes also used below if 1/lhs needed] */
+ if (needbytes>sizeof(dacbuff)) {
+ allocdac=(decNumber *)malloc(needbytes);
+ if (allocdac==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ dac=allocdac; /* use the allocated space */
+ }
+ /* here, aset is set up and accumulator is ready for use */
+
+ if (!useint) { /* non-integral rhs */
+ /* x ** y; special-case x=1 here as it will otherwise always */
+ /* reduce to integer 1; decLnOp has a fastpath which detects */
+ /* the case of x=1 */
+ decLnOp(dac, lhs, &aset, &status); /* dac=ln(lhs) */
+ /* [no error possible, as lhs 0 already handled] */
+ if (ISZERO(dac)) { /* x==1, 1.0, etc. */
+ /* need to return fully-padded 1.0000 etc., but rhsint->1 */
+ *dac->lsu=1; /* was 0, make int 1 */
+ if (!rhsint) { /* add padding */
+ Int shift=set->digits-1;
+ dac->digits=decShiftToMost(dac->lsu, 1, shift);
+ dac->exponent=-shift; /* make 1.0000... */
+ status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
+ }
+ }
+ else {
+ decMultiplyOp(dac, dac, rhs, &aset, &status); /* dac=dac*rhs */
+ decExpOp(dac, dac, &aset, &status); /* dac=exp(dac) */
+ }
+ /* and drop through for final rounding */
+ } /* non-integer rhs */
+
+ else { /* carry on with integer */
+ uprv_decNumberZero(dac); /* acc=1 */
+ *dac->lsu=1; /* .. */
+
+ /* if a negative power the constant 1 is needed, and if not subset */
+ /* invert the lhs now rather than inverting the result later */
+ if (decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
+ decNumber *inv=invbuff; /* asssume use fixed buffer */
+ uprv_decNumberCopy(&dnOne, dac); /* dnOne=1; [needed now or later] */
+ #if DECSUBSET
+ if (set->extended) { /* need to calculate 1/lhs */
+ #endif
+ /* divide lhs into 1, putting result in dac [dac=1/dac] */
+ decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status);
+ /* now locate or allocate space for the inverted lhs */
+ if (needbytes>sizeof(invbuff)) {
+ allocinv=(decNumber *)malloc(needbytes);
+ if (allocinv==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ inv=allocinv; /* use the allocated space */
+ }
+ /* [inv now points to big-enough buffer or allocated storage] */
+ uprv_decNumberCopy(inv, dac); /* copy the 1/lhs */
+ uprv_decNumberCopy(dac, &dnOne); /* restore acc=1 */
+ lhs=inv; /* .. and go forward with new lhs */
+ #if DECSUBSET
+ }
+ #endif
+ }
+
+ /* Raise-to-the-power loop... */
+ seenbit=0; /* set once a 1-bit is encountered */
+ for (i=1;;i++){ /* for each bit [top bit ignored] */
+ /* abandon if had overflow or terminal underflow */
+ if (status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
+ if (status&DEC_Overflow || ISZERO(dac)) break;
+ }
+ /* [the following two lines revealed an optimizer bug in a C++ */
+ /* compiler, with symptom: 5**3 -> 25, when n=n+n was used] */
+ n=n<<1; /* move next bit to testable position */
+ if (n<0) { /* top bit is set */
+ seenbit=1; /* OK, significant bit seen */
+ decMultiplyOp(dac, dac, lhs, &aset, &status); /* dac=dac*x */
+ }
+ if (i==31) break; /* that was the last bit */
+ if (!seenbit) continue; /* no need to square 1 */
+ decMultiplyOp(dac, dac, dac, &aset, &status); /* dac=dac*dac [square] */
+ } /*i*/ /* 32 bits */
+
+ /* complete internal overflow or underflow processing */
+ if (status & (DEC_Overflow|DEC_Underflow)) {
+ #if DECSUBSET
+ /* If subset, and power was negative, reverse the kind of -erflow */
+ /* [1/x not yet done] */
+ if (!set->extended && decNumberIsNegative(rhs)) {
+ if (status & DEC_Overflow)
+ status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal;
+ else { /* trickier -- Underflow may or may not be set */
+ status&=~(DEC_Underflow | DEC_Subnormal); /* [one or both] */
+ status|=DEC_Overflow;
+ }
+ }
+ #endif
+ dac->bits=(dac->bits & ~DECNEG) | bits; /* force correct sign */
+ /* round subnormals [to set.digits rather than aset.digits] */
+ /* or set overflow result similarly as required */
+ decFinalize(dac, set, &residue, &status);
+ uprv_decNumberCopy(res, dac); /* copy to result (is now OK length) */
+ break;
+ }
+
+ #if DECSUBSET
+ if (!set->extended && /* subset math */
+ decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
+ /* so divide result into 1 [dac=1/dac] */
+ decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status);
+ }
+ #endif
+ } /* rhs integer path */
+
+ /* reduce result to the requested length and copy to result */
+ decCopyFit(res, dac, set, &residue, &status);
+ decFinish(res, set, &residue, &status); /* final cleanup */
+ #if DECSUBSET
+ if (!set->extended) decTrim(res, set, 0, 1, &dropped); /* trailing zeros */
+ #endif
+ } while(0); /* end protected */
+
+ if (allocdac!=NULL) free(allocdac); /* drop any storage used */
+ if (allocinv!=NULL) free(allocinv); /* .. */
+ #if DECSUBSET
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ #endif
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberPower */
+
+/* ------------------------------------------------------------------ */
+/* decNumberQuantize -- force exponent to requested value */
+/* */
+/* This computes C = op(A, B), where op adjusts the coefficient */
+/* of C (by rounding or shifting) such that the exponent (-scale) */
+/* of C has exponent of B. The numerical value of C will equal A, */
+/* except for the effects of any rounding that occurred. */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the number with exponent to match */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Unless there is an error or the result is infinite, the exponent */
+/* after the operation is guaranteed to be equal to that of B. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberQuantize(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decQuantizeOp(res, lhs, rhs, set, 1, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberQuantize */
+
+/* ------------------------------------------------------------------ */
+/* decNumberReduce -- remove trailing zeros */
+/* */
+/* This computes C = 0 + A, and normalizes the result */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* Previously known as Normalize */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNormalize(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ return uprv_decNumberReduce(res, rhs, set);
+ } /* decNumberNormalize */
+
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberReduce(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+ uInt status=0; /* as usual */
+ Int residue=0; /* as usual */
+ Int dropped; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* Infinities copy through; NaNs need usual treatment */
+ if (decNumberIsNaN(rhs)) {
+ decNaNs(res, rhs, NULL, set, &status);
+ break;
+ }
+
+ /* reduce result to the requested length and copy to result */
+ decCopyFit(res, rhs, set, &residue, &status); /* copy & round */
+ decFinish(res, set, &residue, &status); /* cleanup/set flags */
+ decTrim(res, set, 1, 0, &dropped); /* normalize in place */
+ /* [may clamp] */
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* .. */
+ #endif
+ if (status!=0) decStatus(res, status, set);/* then report status */
+ return res;
+ } /* decNumberReduce */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRescale -- force exponent to requested value */
+/* */
+/* This computes C = op(A, B), where op adjusts the coefficient */
+/* of C (by rounding or shifting) such that the exponent (-scale) */
+/* of C has the value B. The numerical value of C will equal A, */
+/* except for the effects of any rounding that occurred. */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the requested exponent */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Unless there is an error or the result is infinite, the exponent */
+/* after the operation is guaranteed to be equal to B. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRescale(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decQuantizeOp(res, lhs, rhs, set, 0, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberRescale */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRemainder -- divide and return remainder */
+/* */
+/* This computes C = A % B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X%X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainder(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, REMAINDER, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberRemainder */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRemainderNear -- divide and return remainder from nearest */
+/* */
+/* This computes C = A % B, where % is the IEEE remainder operator */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X%X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainderNear(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, REMNEAR, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberRemainderNear */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRotate -- rotate the coefficient of a Number left/right */
+/* */
+/* This computes C = A rot B (in base ten and rotating set->digits */
+/* digits). */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=XrotX) */
+/* lhs is A */
+/* rhs is B, the number of digits to rotate (-ve to right) */
+/* set is the context */
+/* */
+/* The digits of the coefficient of A are rotated to the left (if B */
+/* is positive) or to the right (if B is negative) without adjusting */
+/* the exponent or the sign of A. If lhs->digits is less than */
+/* set->digits the coefficient is padded with zeros on the left */
+/* before the rotate. Any leading zeros in the result are removed */
+/* as usual. */
+/* */
+/* B must be an integer (q=0) and in the range -set->digits through */
+/* +set->digits. */
+/* C must have space for set->digits digits. */
+/* NaNs are propagated as usual. Infinities are unaffected (but */
+/* B must be valid). No status is set unless B is invalid or an */
+/* operand is an sNaN. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRotate(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ Int rotate; /* rhs as an Int */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* NaNs propagate as normal */
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
+ decNaNs(res, lhs, rhs, set, &status);
+ /* rhs must be an integer */
+ else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
+ status=DEC_Invalid_operation;
+ else { /* both numeric, rhs is an integer */
+ rotate=decGetInt(rhs); /* [cannot fail] */
+ if (rotate==BADINT /* something bad .. */
+ || rotate==BIGODD || rotate==BIGEVEN /* .. very big .. */
+ || abs(rotate)>set->digits) /* .. or out of range */
+ status=DEC_Invalid_operation;
+ else { /* rhs is OK */
+ uprv_decNumberCopy(res, lhs);
+ /* convert -ve rotate to equivalent positive rotation */
+ if (rotate<0) rotate=set->digits+rotate;
+ if (rotate!=0 && rotate!=set->digits /* zero or full rotation */
+ && !decNumberIsInfinite(res)) { /* lhs was infinite */
+ /* left-rotate to do; 0 < rotate < set->digits */
+ uInt units, shift; /* work */
+ uInt msudigits; /* digits in result msu */
+ Unit *msu=res->lsu+D2U(res->digits)-1; /* current msu */
+ Unit *msumax=res->lsu+D2U(set->digits)-1; /* rotation msu */
+ for (msu++; msu<=msumax; msu++) *msu=0; /* ensure high units=0 */
+ res->digits=set->digits; /* now full-length */
+ msudigits=MSUDIGITS(res->digits); /* actual digits in msu */
+
+ /* rotation here is done in-place, in three steps */
+ /* 1. shift all to least up to one unit to unit-align final */
+ /* lsd [any digits shifted out are rotated to the left, */
+ /* abutted to the original msd (which may require split)] */
+ /* */
+ /* [if there are no whole units left to rotate, the */
+ /* rotation is now complete] */
+ /* */
+ /* 2. shift to least, from below the split point only, so that */
+ /* the final msd is in the right place in its Unit [any */
+ /* digits shifted out will fit exactly in the current msu, */
+ /* left aligned, no split required] */
+ /* */
+ /* 3. rotate all the units by reversing left part, right */
+ /* part, and then whole */
+ /* */
+ /* example: rotate right 8 digits (2 units + 2), DECDPUN=3. */
+ /* */
+ /* start: 00a bcd efg hij klm npq */
+ /* */
+ /* 1a 000 0ab cde fgh|ijk lmn [pq saved] */
+ /* 1b 00p qab cde fgh|ijk lmn */
+ /* */
+ /* 2a 00p qab cde fgh|00i jkl [mn saved] */
+ /* 2b mnp qab cde fgh|00i jkl */
+ /* */
+ /* 3a fgh cde qab mnp|00i jkl */
+ /* 3b fgh cde qab mnp|jkl 00i */
+ /* 3c 00i jkl mnp qab cde fgh */
+
+ /* Step 1: amount to shift is the partial right-rotate count */
+ rotate=set->digits-rotate; /* make it right-rotate */
+ units=rotate/DECDPUN; /* whole units to rotate */
+ shift=rotate%DECDPUN; /* left-over digits count */
+ if (shift>0) { /* not an exact number of units */
+ uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
+ decShiftToLeast(res->lsu, D2U(res->digits), shift);
+ if (shift>msudigits) { /* msumax-1 needs >0 digits */
+ uInt rem=save%powers[shift-msudigits];/* split save */
+ *msumax=(Unit)(save/powers[shift-msudigits]); /* and insert */
+ *(msumax-1)=*(msumax-1)
+ +(Unit)(rem*powers[DECDPUN-(shift-msudigits)]); /* .. */
+ }
+ else { /* all fits in msumax */
+ *msumax=*msumax+(Unit)(save*powers[msudigits-shift]); /* [maybe *1] */
+ }
+ } /* digits shift needed */
+
+ /* If whole units to rotate... */
+ if (units>0) { /* some to do */
+ /* Step 2: the units to touch are the whole ones in rotate, */
+ /* if any, and the shift is DECDPUN-msudigits (which may be */
+ /* 0, again) */
+ shift=DECDPUN-msudigits;
+ if (shift>0) { /* not an exact number of units */
+ uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
+ decShiftToLeast(res->lsu, units, shift);
+ *msumax=*msumax+(Unit)(save*powers[msudigits]);
+ } /* partial shift needed */
+
+ /* Step 3: rotate the units array using triple reverse */
+ /* (reversing is easy and fast) */
+ decReverse(res->lsu+units, msumax); /* left part */
+ decReverse(res->lsu, res->lsu+units-1); /* right part */
+ decReverse(res->lsu, msumax); /* whole */
+ } /* whole units to rotate */
+ /* the rotation may have left an undetermined number of zeros */
+ /* on the left, so true length needs to be calculated */
+ res->digits=decGetDigits(res->lsu, msumax-res->lsu+1);
+ } /* rotate needed */
+ } /* rhs OK */
+ } /* numerics */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberRotate */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSameQuantum -- test for equal exponents */
+/* */
+/* res is the result number, which will contain either 0 or 1 */
+/* lhs is a number to test */
+/* rhs is the second (usually a pattern) */
+/* */
+/* No errors are possible and no context is needed. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSameQuantum(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs) {
+ Unit ret=0; /* return value */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, DECUNCONT)) return res;
+ #endif
+
+ if (SPECIALARGS) {
+ if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1;
+ else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1;
+ /* [anything else with a special gives 0] */
+ }
+ else if (lhs->exponent==rhs->exponent) ret=1;
+
+ uprv_decNumberZero(res); /* OK to overwrite an operand now */
+ *res->lsu=ret;
+ return res;
+ } /* decNumberSameQuantum */
+
+/* ------------------------------------------------------------------ */
+/* decNumberScaleB -- multiply by a power of 10 */
+/* */
+/* This computes C = A x 10**B where B is an integer (q=0) with */
+/* maximum magnitude 2*(emax+digits) */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the requested power of ten to use */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* The result may underflow or overflow. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberScaleB(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ Int reqexp; /* requested exponent change [B] */
+ uInt status=0; /* accumulator */
+ Int residue; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* Handle special values except lhs infinite */
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
+ decNaNs(res, lhs, rhs, set, &status);
+ /* rhs must be an integer */
+ else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
+ status=DEC_Invalid_operation;
+ else {
+ /* lhs is a number; rhs is a finite with q==0 */
+ reqexp=decGetInt(rhs); /* [cannot fail] */
+ if (reqexp==BADINT /* something bad .. */
+ || reqexp==BIGODD || reqexp==BIGEVEN /* .. very big .. */
+ || abs(reqexp)>(2*(set->digits+set->emax))) /* .. or out of range */
+ status=DEC_Invalid_operation;
+ else { /* rhs is OK */
+ uprv_decNumberCopy(res, lhs); /* all done if infinite lhs */
+ if (!decNumberIsInfinite(res)) { /* prepare to scale */
+ res->exponent+=reqexp; /* adjust the exponent */
+ residue=0;
+ decFinalize(res, set, &residue, &status); /* .. and check */
+ } /* finite LHS */
+ } /* rhs OK */
+ } /* rhs finite */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberScaleB */
+
+/* ------------------------------------------------------------------ */
+/* decNumberShift -- shift the coefficient of a Number left or right */
+/* */
+/* This computes C = A << B or C = A >> -B (in base ten). */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X<<X) */
+/* lhs is A */
+/* rhs is B, the number of digits to shift (-ve to right) */
+/* set is the context */
+/* */
+/* The digits of the coefficient of A are shifted to the left (if B */
+/* is positive) or to the right (if B is negative) without adjusting */
+/* the exponent or the sign of A. */
+/* */
+/* B must be an integer (q=0) and in the range -set->digits through */
+/* +set->digits. */
+/* C must have space for set->digits digits. */
+/* NaNs are propagated as usual. Infinities are unaffected (but */
+/* B must be valid). No status is set unless B is invalid or an */
+/* operand is an sNaN. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberShift(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ Int shift; /* rhs as an Int */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* NaNs propagate as normal */
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
+ decNaNs(res, lhs, rhs, set, &status);
+ /* rhs must be an integer */
+ else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
+ status=DEC_Invalid_operation;
+ else { /* both numeric, rhs is an integer */
+ shift=decGetInt(rhs); /* [cannot fail] */
+ if (shift==BADINT /* something bad .. */
+ || shift==BIGODD || shift==BIGEVEN /* .. very big .. */
+ || abs(shift)>set->digits) /* .. or out of range */
+ status=DEC_Invalid_operation;
+ else { /* rhs is OK */
+ uprv_decNumberCopy(res, lhs);
+ if (shift!=0 && !decNumberIsInfinite(res)) { /* something to do */
+ if (shift>0) { /* to left */
+ if (shift==set->digits) { /* removing all */
+ *res->lsu=0; /* so place 0 */
+ res->digits=1; /* .. */
+ }
+ else { /* */
+ /* first remove leading digits if necessary */
+ if (res->digits+shift>set->digits) {
+ decDecap(res, res->digits+shift-set->digits);
+ /* that updated res->digits; may have gone to 1 (for a */
+ /* single digit or for zero */
+ }
+ if (res->digits>1 || *res->lsu) /* if non-zero.. */
+ res->digits=decShiftToMost(res->lsu, res->digits, shift);
+ } /* partial left */
+ } /* left */
+ else { /* to right */
+ if (-shift>=res->digits) { /* discarding all */
+ *res->lsu=0; /* so place 0 */
+ res->digits=1; /* .. */
+ }
+ else {
+ decShiftToLeast(res->lsu, D2U(res->digits), -shift);
+ res->digits-=(-shift);
+ }
+ } /* to right */
+ } /* non-0 non-Inf shift */
+ } /* rhs OK */
+ } /* numerics */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberShift */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSquareRoot -- square root operator */
+/* */
+/* This computes C = squareroot(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This uses the following varying-precision algorithm in: */
+/* */
+/* Properly Rounded Variable Precision Square Root, T. E. Hull and */
+/* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */
+/* pp229-237, ACM, September 1985. */
+/* */
+/* The square-root is calculated using Newton's method, after which */
+/* a check is made to ensure the result is correctly rounded. */
+/* */
+/* % [Reformatted original Numerical Turing source code follows.] */
+/* function sqrt(x : real) : real */
+/* % sqrt(x) returns the properly rounded approximation to the square */
+/* % root of x, in the precision of the calling environment, or it */
+/* % fails if x < 0. */
+/* % t e hull and a abrham, august, 1984 */
+/* if x <= 0 then */
+/* if x < 0 then */
+/* assert false */
+/* else */
+/* result 0 */
+/* end if */
+/* end if */
+/* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */
+/* var e := getexp(x) % exponent part of x */
+/* var approx : real */
+/* if e mod 2 = 0 then */
+/* approx := .259 + .819 * f % approx to root of f */
+/* else */
+/* f := f/l0 % adjustments */
+/* e := e + 1 % for odd */
+/* approx := .0819 + 2.59 * f % exponent */
+/* end if */
+/* */
+/* var p:= 3 */
+/* const maxp := currentprecision + 2 */
+/* loop */
+/* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */
+/* precision p */
+/* approx := .5 * (approx + f/approx) */
+/* exit when p = maxp */
+/* end loop */
+/* */
+/* % approx is now within 1 ulp of the properly rounded square root */
+/* % of f; to ensure proper rounding, compare squares of (approx - */
+/* % l/2 ulp) and (approx + l/2 ulp) with f. */
+/* p := currentprecision */
+/* begin */
+/* precision p + 2 */
+/* const approxsubhalf := approx - setexp(.5, -p) */
+/* if mulru(approxsubhalf, approxsubhalf) > f then */
+/* approx := approx - setexp(.l, -p + 1) */
+/* else */
+/* const approxaddhalf := approx + setexp(.5, -p) */
+/* if mulrd(approxaddhalf, approxaddhalf) < f then */
+/* approx := approx + setexp(.l, -p + 1) */
+/* end if */
+/* end if */
+/* end */
+/* result setexp(approx, e div 2) % fix exponent */
+/* end sqrt */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSquareRoot(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decContext workset, approxset; /* work contexts */
+ decNumber dzero; /* used for constant zero */
+ Int maxp; /* largest working precision */
+ Int workp; /* working precision */
+ Int residue=0; /* rounding residue */
+ uInt status=0, ignore=0; /* status accumulators */
+ uInt rstatus; /* .. */
+ Int exp; /* working exponent */
+ Int ideal; /* ideal (preferred) exponent */
+ Int needbytes; /* work */
+ Int dropped; /* .. */
+
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+ /* buffer for f [needs +1 in case DECBUFFER 0] */
+ decNumber buff[D2N(DECBUFFER+1)];
+ /* buffer for a [needs +2 to match likely maxp] */
+ decNumber bufa[D2N(DECBUFFER+2)];
+ /* buffer for temporary, b [must be same size as a] */
+ decNumber bufb[D2N(DECBUFFER+2)];
+ decNumber *allocbuff=NULL; /* -> allocated buff, iff allocated */
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
+ decNumber *f=buff; /* reduced fraction */
+ decNumber *a=bufa; /* approximation to result */
+ decNumber *b=bufb; /* intermediate result */
+ /* buffer for temporary variable, up to 3 digits */
+ decNumber buft[D2N(3)];
+ decNumber *t=buft; /* up-to-3-digit constant or work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ /* [Note: 'f' allocation below could reuse this buffer if */
+ /* used, but as this is rare they are kept separate for clarity.] */
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* handle infinities and NaNs */
+ if (SPECIALARG) {
+ if (decNumberIsInfinite(rhs)) { /* an infinity */
+ if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation;
+ else uprv_decNumberCopy(res, rhs); /* +Infinity */
+ }
+ else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
+ break;
+ }
+
+ /* calculate the ideal (preferred) exponent [floor(exp/2)] */
+ /* [It would be nicer to write: ideal=rhs->exponent>>1, but this */
+ /* generates a compiler warning. Generated code is the same.] */
+ ideal=(rhs->exponent&~1)/2; /* target */
+
+ /* handle zeros */
+ if (ISZERO(rhs)) {
+ uprv_decNumberCopy(res, rhs); /* could be 0 or -0 */
+ res->exponent=ideal; /* use the ideal [safe] */
+ /* use decFinish to clamp any out-of-range exponent, etc. */
+ decFinish(res, set, &residue, &status);
+ break;
+ }
+
+ /* any other -x is an oops */
+ if (decNumberIsNegative(rhs)) {
+ status|=DEC_Invalid_operation;
+ break;
+ }
+
+ /* space is needed for three working variables */
+ /* f -- the same precision as the RHS, reduced to 0.01->0.99... */
+ /* a -- Hull's approximation -- precision, when assigned, is */
+ /* currentprecision+1 or the input argument precision, */
+ /* whichever is larger (+2 for use as temporary) */
+ /* b -- intermediate temporary result (same size as a) */
+ /* if any is too long for local storage, then allocate */
+ workp=MAXI(set->digits+1, rhs->digits); /* actual rounding precision */
+ workp=MAXI(workp, 7); /* at least 7 for low cases */
+ maxp=workp+2; /* largest working precision */
+
+ needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
+ if (needbytes>(Int)sizeof(buff)) {
+ allocbuff=(decNumber *)malloc(needbytes);
+ if (allocbuff==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ f=allocbuff; /* use the allocated space */
+ }
+ /* a and b both need to be able to hold a maxp-length number */
+ needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit);
+ if (needbytes>(Int)sizeof(bufa)) { /* [same applies to b] */
+ allocbufa=(decNumber *)malloc(needbytes);
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL || allocbufb==NULL) { /* hopeless */
+ status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated spaces */
+ b=allocbufb; /* .. */
+ }
+
+ /* copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 */
+ uprv_decNumberCopy(f, rhs);
+ exp=f->exponent+f->digits; /* adjusted to Hull rules */
+ f->exponent=-(f->digits); /* to range */
+
+ /* set up working context */
+ uprv_decContextDefault(&workset, DEC_INIT_DECIMAL64);
+ workset.emax=DEC_MAX_EMAX;
+ workset.emin=DEC_MIN_EMIN;
+
+ /* [Until further notice, no error is possible and status bits */
+ /* (Rounded, etc.) should be ignored, not accumulated.] */
+
+ /* Calculate initial approximation, and allow for odd exponent */
+ workset.digits=workp; /* p for initial calculation */
+ t->bits=0; t->digits=3;
+ a->bits=0; a->digits=3;
+ if ((exp & 1)==0) { /* even exponent */
+ /* Set t=0.259, a=0.819 */
+ t->exponent=-3;
+ a->exponent=-3;
+ #if DECDPUN>=3
+ t->lsu[0]=259;
+ a->lsu[0]=819;
+ #elif DECDPUN==2
+ t->lsu[0]=59; t->lsu[1]=2;
+ a->lsu[0]=19; a->lsu[1]=8;
+ #else
+ t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2;
+ a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8;
+ #endif
+ }
+ else { /* odd exponent */
+ /* Set t=0.0819, a=2.59 */
+ f->exponent--; /* f=f/10 */
+ exp++; /* e=e+1 */
+ t->exponent=-4;
+ a->exponent=-2;
+ #if DECDPUN>=3
+ t->lsu[0]=819;
+ a->lsu[0]=259;
+ #elif DECDPUN==2
+ t->lsu[0]=19; t->lsu[1]=8;
+ a->lsu[0]=59; a->lsu[1]=2;
+ #else
+ t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8;
+ a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2;
+ #endif
+ }
+
+ decMultiplyOp(a, a, f, &workset, &ignore); /* a=a*f */
+ decAddOp(a, a, t, &workset, 0, &ignore); /* ..+t */
+ /* [a is now the initial approximation for sqrt(f), calculated with */
+ /* currentprecision, which is also a's precision.] */
+
+ /* the main calculation loop */
+ uprv_decNumberZero(&dzero); /* make 0 */
+ uprv_decNumberZero(t); /* set t = 0.5 */
+ t->lsu[0]=5; /* .. */
+ t->exponent=-1; /* .. */
+ workset.digits=3; /* initial p */
+ for (; workset.digits<maxp;) {
+ /* set p to min(2*p - 2, maxp) [hence 3; or: 4, 6, 10, ... , maxp] */
+ workset.digits=MINI(workset.digits*2-2, maxp);
+ /* a = 0.5 * (a + f/a) */
+ /* [calculated at p then rounded to currentprecision] */
+ decDivideOp(b, f, a, &workset, DIVIDE, &ignore); /* b=f/a */
+ decAddOp(b, b, a, &workset, 0, &ignore); /* b=b+a */
+ decMultiplyOp(a, b, t, &workset, &ignore); /* a=b*0.5 */
+ } /* loop */
+
+ /* Here, 0.1 <= a < 1 [Hull], and a has maxp digits */
+ /* now reduce to length, etc.; this needs to be done with a */
+ /* having the correct exponent so as to handle subnormals */
+ /* correctly */
+ approxset=*set; /* get emin, emax, etc. */
+ approxset.round=DEC_ROUND_HALF_EVEN;
+ a->exponent+=exp/2; /* set correct exponent */
+ rstatus=0; /* clear status */
+ residue=0; /* .. and accumulator */
+ decCopyFit(a, a, &approxset, &residue, &rstatus); /* reduce (if needed) */
+ decFinish(a, &approxset, &residue, &rstatus); /* clean and finalize */
+
+ /* Overflow was possible if the input exponent was out-of-range, */
+ /* in which case quit */
+ if (rstatus&DEC_Overflow) {
+ status=rstatus; /* use the status as-is */
+ uprv_decNumberCopy(res, a); /* copy to result */
+ break;
+ }
+
+ /* Preserve status except Inexact/Rounded */
+ status|=(rstatus & ~(DEC_Rounded|DEC_Inexact));
+
+ /* Carry out the Hull correction */
+ a->exponent-=exp/2; /* back to 0.1->1 */
+
+ /* a is now at final precision and within 1 ulp of the properly */
+ /* rounded square root of f; to ensure proper rounding, compare */
+ /* squares of (a - l/2 ulp) and (a + l/2 ulp) with f. */
+ /* Here workset.digits=maxp and t=0.5, and a->digits determines */
+ /* the ulp */
+ workset.digits--; /* maxp-1 is OK now */
+ t->exponent=-a->digits-1; /* make 0.5 ulp */
+ decAddOp(b, a, t, &workset, DECNEG, &ignore); /* b = a - 0.5 ulp */
+ workset.round=DEC_ROUND_UP;
+ decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulru(b, b) */
+ decCompareOp(b, f, b, &workset, COMPARE, &ignore); /* b ? f, reversed */
+ if (decNumberIsNegative(b)) { /* f < b [i.e., b > f] */
+ /* this is the more common adjustment, though both are rare */
+ t->exponent++; /* make 1.0 ulp */
+ t->lsu[0]=1; /* .. */
+ decAddOp(a, a, t, &workset, DECNEG, &ignore); /* a = a - 1 ulp */
+ /* assign to approx [round to length] */
+ approxset.emin-=exp/2; /* adjust to match a */
+ approxset.emax-=exp/2;
+ decAddOp(a, &dzero, a, &approxset, 0, &ignore);
+ }
+ else {
+ decAddOp(b, a, t, &workset, 0, &ignore); /* b = a + 0.5 ulp */
+ workset.round=DEC_ROUND_DOWN;
+ decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulrd(b, b) */
+ decCompareOp(b, b, f, &workset, COMPARE, &ignore); /* b ? f */
+ if (decNumberIsNegative(b)) { /* b < f */
+ t->exponent++; /* make 1.0 ulp */
+ t->lsu[0]=1; /* .. */
+ decAddOp(a, a, t, &workset, 0, &ignore); /* a = a + 1 ulp */
+ /* assign to approx [round to length] */
+ approxset.emin-=exp/2; /* adjust to match a */
+ approxset.emax-=exp/2;
+ decAddOp(a, &dzero, a, &approxset, 0, &ignore);
+ }
+ }
+ /* [no errors are possible in the above, and rounding/inexact during */
+ /* estimation are irrelevant, so status was not accumulated] */
+
+ /* Here, 0.1 <= a < 1 (still), so adjust back */
+ a->exponent+=exp/2; /* set correct exponent */
+
+ /* count droppable zeros [after any subnormal rounding] by */
+ /* trimming a copy */
+ uprv_decNumberCopy(b, a);
+ decTrim(b, set, 1, 1, &dropped); /* [drops trailing zeros] */
+
+ /* Set Inexact and Rounded. The answer can only be exact if */
+ /* it is short enough so that squaring it could fit in workp */
+ /* digits, so this is the only (relatively rare) condition that */
+ /* a careful check is needed */
+ if (b->digits*2-1 > workp) { /* cannot fit */
+ status|=DEC_Inexact|DEC_Rounded;
+ }
+ else { /* could be exact/unrounded */
+ uInt mstatus=0; /* local status */
+ decMultiplyOp(b, b, b, &workset, &mstatus); /* try the multiply */
+ if (mstatus&DEC_Overflow) { /* result just won't fit */
+ status|=DEC_Inexact|DEC_Rounded;
+ }
+ else { /* plausible */
+ decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); /* b ? rhs */
+ if (!ISZERO(t)) status|=DEC_Inexact|DEC_Rounded; /* not equal */
+ else { /* is Exact */
+ /* here, dropped is the count of trailing zeros in 'a' */
+ /* use closest exponent to ideal... */
+ Int todrop=ideal-a->exponent; /* most that can be dropped */
+ if (todrop<0) status|=DEC_Rounded; /* ideally would add 0s */
+ else { /* unrounded */
+ /* there are some to drop, but emax may not allow all */
+ Int maxexp=set->emax-set->digits+1;
+ Int maxdrop=maxexp-a->exponent;
+ if (todrop>maxdrop && set->clamp) { /* apply clamping */
+ todrop=maxdrop;
+ status|=DEC_Clamped;
+ }
+ if (dropped<todrop) { /* clamp to those available */
+ todrop=dropped;
+ status|=DEC_Clamped;
+ }
+ if (todrop>0) { /* have some to drop */
+ decShiftToLeast(a->lsu, D2U(a->digits), todrop);
+ a->exponent+=todrop; /* maintain numerical value */
+ a->digits-=todrop; /* new length */
+ }
+ }
+ }
+ }
+ }
+
+ /* double-check Underflow, as perhaps the result could not have */
+ /* been subnormal (initial argument too big), or it is now Exact */
+ if (status&DEC_Underflow) {
+ Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
+ /* check if truly subnormal */
+ #if DECEXTFLAG /* DEC_Subnormal too */
+ if (ae>=set->emin*2) status&=~(DEC_Subnormal|DEC_Underflow);
+ #else
+ if (ae>=set->emin*2) status&=~DEC_Underflow;
+ #endif
+ /* check if truly inexact */
+ if (!(status&DEC_Inexact)) status&=~DEC_Underflow;
+ }
+
+ uprv_decNumberCopy(res, a); /* a is now the result */
+ } while(0); /* end protected */
+
+ if (allocbuff!=NULL) free(allocbuff); /* drop any storage used */
+ if (allocbufa!=NULL) free(allocbufa); /* .. */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* .. */
+ #endif
+ if (status!=0) decStatus(res, status, set);/* then report status */
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberSquareRoot */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSubtract -- subtract two Numbers */
+/* */
+/* This computes C = A - B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X-X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSubtract(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+
+ decAddOp(res, lhs, rhs, set, DECNEG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberSubtract */
+
+/* ------------------------------------------------------------------ */
+/* decNumberToIntegralExact -- round-to-integral-value with InExact */
+/* decNumberToIntegralValue -- round-to-integral-value */
+/* */
+/* res is the result */
+/* rhs is input number */
+/* set is the context */
+/* */
+/* res must have space for any value of rhs. */
+/* */
+/* This implements the IEEE special operators and therefore treats */
+/* special values as valid. For finite numbers it returns */
+/* rescale(rhs, 0) if rhs->exponent is <0. */
+/* Otherwise the result is rhs (so no error is possible, except for */
+/* sNaN). */
+/* */
+/* The context is used for rounding mode and status after sNaN, but */
+/* the digits setting is ignored. The Exact version will signal */
+/* Inexact if the result differs numerically from rhs; the other */
+/* never signals Inexact. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dn;
+ decContext workset; /* working context */
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* handle infinities and NaNs */
+ if (SPECIALARG) {
+ if (decNumberIsInfinite(rhs)) uprv_decNumberCopy(res, rhs); /* an Infinity */
+ else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
+ }
+ else { /* finite */
+ /* have a finite number; no error possible (res must be big enough) */
+ if (rhs->exponent>=0) return uprv_decNumberCopy(res, rhs);
+ /* that was easy, but if negative exponent there is work to do... */
+ workset=*set; /* clone rounding, etc. */
+ workset.digits=rhs->digits; /* no length rounding */
+ workset.traps=0; /* no traps */
+ uprv_decNumberZero(&dn); /* make a number with exponent 0 */
+ uprv_decNumberQuantize(res, rhs, &dn, &workset);
+ status|=workset.status;
+ }
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberToIntegralExact */
+
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decContext workset=*set; /* working context */
+ workset.traps=0; /* no traps */
+ uprv_decNumberToIntegralExact(res, rhs, &workset);
+ /* this never affects set, except for sNaNs; NaN will have been set */
+ /* or propagated already, so no need to call decStatus */
+ set->status|=workset.status&DEC_Invalid_operation;
+ return res;
+ } /* decNumberToIntegralValue */
+
+/* ------------------------------------------------------------------ */
+/* decNumberXor -- XOR two Numbers, digitwise */
+/* */
+/* This computes C = A ^ B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X^X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberXor(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ const Unit *ua, *ub; /* -> operands */
+ const Unit *msua, *msub; /* -> operand msus */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
+ || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ /* operands are valid */
+ ua=lhs->lsu; /* bottom-up */
+ ub=rhs->lsu; /* .. */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
+ msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
+ Unit a, b; /* extract units */
+ if (ua>msua) a=0;
+ else a=*ua;
+ if (ub>msub) b=0;
+ else b=*ub;
+ *uc=0; /* can now write back */
+ if (a|b) { /* maybe 1 bits to examine */
+ Int i, j;
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if ((a^b)&1) *uc=*uc+(Unit)powers[i]; /* effect XOR */
+ j=a%10;
+ a=a/10;
+ j|=b%10;
+ b=b/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* non-zero */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, uc-res->lsu);
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberXor */
+
+
+/* ================================================================== */
+/* Utility routines */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* decNumberClass -- return the decClass of a decNumber */
+/* dn -- the decNumber to test */
+/* set -- the context to use for Emin */
+/* returns the decClass enum */
+/* ------------------------------------------------------------------ */
+enum decClass uprv_decNumberClass(const decNumber *dn, decContext *set) {
+ if (decNumberIsSpecial(dn)) {
+ if (decNumberIsQNaN(dn)) return DEC_CLASS_QNAN;
+ if (decNumberIsSNaN(dn)) return DEC_CLASS_SNAN;
+ /* must be an infinity */
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_INF;
+ return DEC_CLASS_POS_INF;
+ }
+ /* is finite */
+ if (uprv_decNumberIsNormal(dn, set)) { /* most common */
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_NORMAL;
+ return DEC_CLASS_POS_NORMAL;
+ }
+ /* is subnormal or zero */
+ if (decNumberIsZero(dn)) { /* most common */
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_ZERO;
+ return DEC_CLASS_POS_ZERO;
+ }
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_SUBNORMAL;
+ return DEC_CLASS_POS_SUBNORMAL;
+ } /* decNumberClass */
+
+/* ------------------------------------------------------------------ */
+/* decNumberClassToString -- convert decClass to a string */
+/* */
+/* eclass is a valid decClass */
+/* returns a constant string describing the class (max 13+1 chars) */
+/* ------------------------------------------------------------------ */
+const char *uprv_decNumberClassToString(enum decClass eclass) {
+ if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN;
+ if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN;
+ if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ;
+ if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ;
+ if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS;
+ if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS;
+ if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI;
+ if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI;
+ if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN;
+ if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN;
+ return DEC_ClassString_UN; /* Unknown */
+ } /* decNumberClassToString */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopy -- copy a number */
+/* */
+/* dest is the target decNumber */
+/* src is the source decNumber */
+/* returns dest */
+/* */
+/* (dest==src is allowed and is a no-op) */
+/* All fields are updated as required. This is a utility operation, */
+/* so special values are unchanged and no error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopy(decNumber *dest, const decNumber *src) {
+
+ #if DECCHECK
+ if (src==NULL) return uprv_decNumberZero(dest);
+ #endif
+
+ if (dest==src) return dest; /* no copy required */
+
+ /* Use explicit assignments here as structure assignment could copy */
+ /* more than just the lsu (for small DECDPUN). This would not affect */
+ /* the value of the results, but could disturb test harness spill */
+ /* checking. */
+ dest->bits=src->bits;
+ dest->exponent=src->exponent;
+ dest->digits=src->digits;
+ dest->lsu[0]=src->lsu[0];
+ if (src->digits>DECDPUN) { /* more Units to come */
+ const Unit *smsup, *s; /* work */
+ Unit *d; /* .. */
+ /* memcpy for the remaining Units would be safe as they cannot */
+ /* overlap. However, this explicit loop is faster in short cases. */
+ d=dest->lsu+1; /* -> first destination */
+ smsup=src->lsu+D2U(src->digits); /* -> source msu+1 */
+ for (s=src->lsu+1; s<smsup; s++, d++) *d=*s;
+ }
+ return dest;
+ } /* decNumberCopy */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopyAbs -- quiet absolute value operator */
+/* */
+/* This sets C = abs(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* */
+/* C must have space for set->digits digits. */
+/* No exception or error can occur; this is a quiet bitwise operation.*/
+/* See also decNumberAbs for a checking version of this. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
+ #endif
+ uprv_decNumberCopy(res, rhs);
+ res->bits&=~DECNEG; /* turn off sign */
+ return res;
+ } /* decNumberCopyAbs */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopyNegate -- quiet negate value operator */
+/* */
+/* This sets C = negate(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* */
+/* C must have space for set->digits digits. */
+/* No exception or error can occur; this is a quiet bitwise operation.*/
+/* See also decNumberMinus for a checking version of this. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
+ #endif
+ uprv_decNumberCopy(res, rhs);
+ res->bits^=DECNEG; /* invert the sign */
+ return res;
+ } /* decNumberCopyNegate */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopySign -- quiet copy and set sign operator */
+/* */
+/* This sets C = A with the sign of B */
+/* */
+/* res is C, the result. C may be A */
+/* lhs is A */
+/* rhs is B */
+/* */
+/* C must have space for set->digits digits. */
+/* No exception or error can occur; this is a quiet bitwise operation.*/
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopySign(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs) {
+ uByte sign; /* rhs sign */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
+ #endif
+ sign=rhs->bits & DECNEG; /* save sign bit */
+ uprv_decNumberCopy(res, lhs);
+ res->bits&=~DECNEG; /* clear the sign */
+ res->bits|=sign; /* set from rhs */
+ return res;
+ } /* decNumberCopySign */
+
+/* ------------------------------------------------------------------ */
+/* decNumberGetBCD -- get the coefficient in BCD8 */
+/* dn is the source decNumber */
+/* bcd is the uInt array that will receive dn->digits BCD bytes, */
+/* most-significant at offset 0 */
+/* returns bcd */
+/* */
+/* bcd must have at least dn->digits bytes. No error is possible; if */
+/* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */
+/* ------------------------------------------------------------------ */
+U_CAPI uByte * U_EXPORT2 uprv_decNumberGetBCD(const decNumber *dn, uByte *bcd) {
+ uByte *ub=bcd+dn->digits-1; /* -> lsd */
+ const Unit *up=dn->lsu; /* Unit pointer, -> lsu */
+
+ #if DECDPUN==1 /* trivial simple copy */
+ for (; ub>=bcd; ub--, up++) *ub=*up;
+ #else /* chopping needed */
+ uInt u=*up; /* work */
+ uInt cut=DECDPUN; /* downcounter through unit */
+ for (; ub>=bcd; ub--) {
+ *ub=(uByte)(u%10); /* [*6554 trick inhibits, here] */
+ u=u/10;
+ cut--;
+ if (cut>0) continue; /* more in this unit */
+ up++;
+ u=*up;
+ cut=DECDPUN;
+ }
+ #endif
+ return bcd;
+ } /* decNumberGetBCD */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSetBCD -- set (replace) the coefficient from BCD8 */
+/* dn is the target decNumber */
+/* bcd is the uInt array that will source n BCD bytes, most- */
+/* significant at offset 0 */
+/* n is the number of digits in the source BCD array (bcd) */
+/* returns dn */
+/* */
+/* dn must have space for at least n digits. No error is possible; */
+/* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */
+/* and bcd[0] zero. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) {
+ Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [target pointer] */
+ const uByte *ub=bcd; /* -> source msd */
+
+ #if DECDPUN==1 /* trivial simple copy */
+ for (; ub<bcd+n; ub++, up--) *up=*ub;
+ #else /* some assembly needed */
+ /* calculate how many digits in msu, and hence first cut */
+ Int cut=MSUDIGITS(n); /* [faster than remainder] */
+ for (;up>=dn->lsu; up--) { /* each Unit from msu */
+ *up=0; /* will take <=DECDPUN digits */
+ for (; cut>0; ub++, cut--) *up=X10(*up)+*ub;
+ cut=DECDPUN; /* next Unit has all digits */
+ }
+ #endif
+ dn->digits=n; /* set digit count */
+ return dn;
+ } /* decNumberSetBCD */
+
+/* ------------------------------------------------------------------ */
+/* decNumberIsNormal -- test normality of a decNumber */
+/* dn is the decNumber to test */
+/* set is the context to use for Emin */
+/* returns 1 if |dn| is finite and >=Nmin, 0 otherwise */
+/* ------------------------------------------------------------------ */
+Int uprv_decNumberIsNormal(const decNumber *dn, decContext *set) {
+ Int ae; /* adjusted exponent */
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+
+ if (decNumberIsSpecial(dn)) return 0; /* not finite */
+ if (decNumberIsZero(dn)) return 0; /* not non-zero */
+
+ ae=dn->exponent+dn->digits-1; /* adjusted exponent */
+ if (ae<set->emin) return 0; /* is subnormal */
+ return 1;
+ } /* decNumberIsNormal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberIsSubnormal -- test subnormality of a decNumber */
+/* dn is the decNumber to test */
+/* set is the context to use for Emin */
+/* returns 1 if |dn| is finite, non-zero, and <Nmin, 0 otherwise */
+/* ------------------------------------------------------------------ */
+Int uprv_decNumberIsSubnormal(const decNumber *dn, decContext *set) {
+ Int ae; /* adjusted exponent */
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+
+ if (decNumberIsSpecial(dn)) return 0; /* not finite */
+ if (decNumberIsZero(dn)) return 0; /* not non-zero */
+
+ ae=dn->exponent+dn->digits-1; /* adjusted exponent */
+ if (ae<set->emin) return 1; /* is subnormal */
+ return 0;
+ } /* decNumberIsSubnormal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberTrim -- remove insignificant zeros */
+/* */
+/* dn is the number to trim */
+/* returns dn */
+/* */
+/* All fields are updated as required. This is a utility operation, */
+/* so special values are unchanged and no error is possible. The */
+/* zeros are removed unconditionally. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberTrim(decNumber *dn) {
+ Int dropped; /* work */
+ decContext set; /* .. */
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, DECUNCONT)) return dn;
+ #endif
+ uprv_decContextDefault(&set, DEC_INIT_BASE); /* clamp=0 */
+ return decTrim(dn, &set, 0, 1, &dropped);
+ } /* decNumberTrim */
+
+/* ------------------------------------------------------------------ */
+/* decNumberVersion -- return the name and version of this module */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+const char * uprv_decNumberVersion(void) {
+ return DECVERSION;
+ } /* decNumberVersion */
+
+/* ------------------------------------------------------------------ */
+/* decNumberZero -- set a number to 0 */
+/* */
+/* dn is the number to set, with space for one digit */
+/* returns dn */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+/* Memset is not used as it is much slower in some environments. */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberZero(decNumber *dn) {
+
+ #if DECCHECK
+ if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
+ #endif
+
+ dn->bits=0;
+ dn->exponent=0;
+ dn->digits=1;
+ dn->lsu[0]=0;
+ return dn;
+ } /* decNumberZero */
+
+/* ================================================================== */
+/* Local routines */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* decToString -- lay out a number into a string */
+/* */
+/* dn is the number to lay out */
+/* string is where to lay out the number */
+/* eng is 1 if Engineering, 0 if Scientific */
+/* */
+/* string must be at least dn->digits+14 characters long */
+/* No error is possible. */
+/* */
+/* Note that this routine can generate a -0 or 0.000. These are */
+/* never generated in subset to-number or arithmetic, but can occur */
+/* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */
+/* ------------------------------------------------------------------ */
+/* If DECCHECK is enabled the string "?" is returned if a number is */
+/* invalid. */
+static void decToString(const decNumber *dn, char *string, Flag eng) {
+ Int exp=dn->exponent; /* local copy */
+ Int e; /* E-part value */
+ Int pre; /* digits before the '.' */
+ Int cut; /* for counting digits in a Unit */
+ char *c=string; /* work [output pointer] */
+ const Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [input pointer] */
+ uInt u, pow; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, dn, DECUNUSED, DECUNCONT)) {
+ strcpy(string, "?");
+ return;}
+ #endif
+
+ if (decNumberIsNegative(dn)) { /* Negatives get a minus */
+ *c='-';
+ c++;
+ }
+ if (dn->bits&DECSPECIAL) { /* Is a special value */
+ if (decNumberIsInfinite(dn)) {
+ strcpy(c, "Inf");
+ strcpy(c+3, "inity");
+ return;}
+ /* a NaN */
+ if (dn->bits&DECSNAN) { /* signalling NaN */
+ *c='s';
+ c++;
+ }
+ strcpy(c, "NaN");
+ c+=3; /* step past */
+ /* if not a clean non-zero coefficient, that's all there is in a */
+ /* NaN string */
+ if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return;
+ /* [drop through to add integer] */
+ }
+
+ /* calculate how many digits in msu, and hence first cut */
+ cut=MSUDIGITS(dn->digits); /* [faster than remainder] */
+ cut--; /* power of ten for digit */
+
+ if (exp==0) { /* simple integer [common fastpath] */
+ for (;up>=dn->lsu; up--) { /* each Unit from msu */
+ u=*up; /* contains DECDPUN digits to lay out */
+ for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow);
+ cut=DECDPUN-1; /* next Unit has all digits */
+ }
+ *c='\0'; /* terminate the string */
+ return;}
+
+ /* non-0 exponent -- assume plain form */
+ pre=dn->digits+exp; /* digits before '.' */
+ e=0; /* no E */
+ if ((exp>0) || (pre<-5)) { /* need exponential form */
+ e=exp+dn->digits-1; /* calculate E value */
+ pre=1; /* assume one digit before '.' */
+ if (eng && (e!=0)) { /* engineering: may need to adjust */
+ Int adj; /* adjustment */
+ /* The C remainder operator is undefined for negative numbers, so */
+ /* a positive remainder calculation must be used here */
+ if (e<0) {
+ adj=(-e)%3;
+ if (adj!=0) adj=3-adj;
+ }
+ else { /* e>0 */
+ adj=e%3;
+ }
+ e=e-adj;
+ /* if dealing with zero still produce an exponent which is a */
+ /* multiple of three, as expected, but there will only be the */
+ /* one zero before the E, still. Otherwise note the padding. */
+ if (!ISZERO(dn)) pre+=adj;
+ else { /* is zero */
+ if (adj!=0) { /* 0.00Esnn needed */
+ e=e+3;
+ pre=-(2-adj);
+ }
+ } /* zero */
+ } /* eng */
+ } /* need exponent */
+
+ /* lay out the digits of the coefficient, adding 0s and . as needed */
+ u=*up;
+ if (pre>0) { /* xxx.xxx or xx00 (engineering) form */
+ Int n=pre;
+ for (; pre>0; pre--, c++, cut--) {
+ if (cut<0) { /* need new Unit */
+ if (up==dn->lsu) break; /* out of input digits (pre>digits) */
+ up--;
+ cut=DECDPUN-1;
+ u=*up;
+ }
+ TODIGIT(u, cut, c, pow);
+ }
+ if (n<dn->digits) { /* more to come, after '.' */
+ *c='.'; c++;
+ for (;; c++, cut--) {
+ if (cut<0) { /* need new Unit */
+ if (up==dn->lsu) break; /* out of input digits */
+ up--;
+ cut=DECDPUN-1;
+ u=*up;
+ }
+ TODIGIT(u, cut, c, pow);
+ }
+ }
+ else for (; pre>0; pre--, c++) *c='0'; /* 0 padding (for engineering) needed */
+ }
+ else { /* 0.xxx or 0.000xxx form */
+ *c='0'; c++;
+ *c='.'; c++;
+ for (; pre<0; pre++, c++) *c='0'; /* add any 0's after '.' */
+ for (; ; c++, cut--) {
+ if (cut<0) { /* need new Unit */
+ if (up==dn->lsu) break; /* out of input digits */
+ up--;
+ cut=DECDPUN-1;
+ u=*up;
+ }
+ TODIGIT(u, cut, c, pow);
+ }
+ }
+
+ /* Finally add the E-part, if needed. It will never be 0, has a
+ base maximum and minimum of +999999999 through -999999999, but
+ could range down to -1999999998 for anormal numbers */
+ if (e!=0) {
+ Flag had=0; /* 1=had non-zero */
+ *c='E'; c++;
+ *c='+'; c++; /* assume positive */
+ u=e; /* .. */
+ if (e<0) {
+ *(c-1)='-'; /* oops, need - */
+ u=-e; /* uInt, please */
+ }
+ /* lay out the exponent [_itoa or equivalent is not ANSI C] */
+ for (cut=9; cut>=0; cut--) {
+ TODIGIT(u, cut, c, pow);
+ if (*c=='0' && !had) continue; /* skip leading zeros */
+ had=1; /* had non-0 */
+ c++; /* step for next */
+ } /* cut */
+ }
+ *c='\0'; /* terminate the string (all paths) */
+ return;
+ } /* decToString */
+
+/* ------------------------------------------------------------------ */
+/* decAddOp -- add/subtract operation */
+/* */
+/* This computes C = A + B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* negate is DECNEG if rhs should be negated, or 0 otherwise */
+/* status accumulates status for the caller */
+/* */
+/* C must have space for set->digits digits. */
+/* Inexact in status must be 0 for correct Exact zero sign in result */
+/* ------------------------------------------------------------------ */
+/* If possible, the coefficient is calculated directly into C. */
+/* However, if: */
+/* -- a digits+1 calculation is needed because the numbers are */
+/* unaligned and span more than set->digits digits */
+/* -- a carry to digits+1 digits looks possible */
+/* -- C is the same as A or B, and the result would destructively */
+/* overlap the A or B coefficient */
+/* then the result must be calculated into a temporary buffer. In */
+/* this case a local (stack) buffer is used if possible, and only if */
+/* too long for that does malloc become the final resort. */
+/* */
+/* Misalignment is handled as follows: */
+/* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */
+/* BPad: Apply the padding by a combination of shifting (whole */
+/* units) and multiplication (part units). */
+/* */
+/* Addition, especially x=x+1, is speed-critical. */
+/* The static buffer is larger than might be expected to allow for */
+/* calls from higher-level funtions (notable exp). */
+/* ------------------------------------------------------------------ */
+static decNumber * decAddOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ uByte negate, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ Int rhsshift; /* working shift (in Units) */
+ Int maxdigits; /* longest logical length */
+ Int mult; /* multiplier */
+ Int residue; /* rounding accumulator */
+ uByte bits; /* result bits */
+ Flag diffsign; /* non-0 if arguments have different sign */
+ Unit *acc; /* accumulator for result */
+ Unit accbuff[SD2U(DECBUFFER*2+20)]; /* local buffer [*2+20 reduces many */
+ /* allocations when called from */
+ /* other operations, notable exp] */
+ Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
+ Int reqdigits=set->digits; /* local copy; requested DIGITS */
+ Int padding; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* note whether signs differ [used all paths] */
+ diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG);
+
+ /* handle infinities and NaNs */
+ if (SPECIALARGS) { /* a special bit set */
+ if (SPECIALARGS & (DECSNAN | DECNAN)) /* a NaN */
+ decNaNs(res, lhs, rhs, set, status);
+ else { /* one or two infinities */
+ if (decNumberIsInfinite(lhs)) { /* LHS is infinity */
+ /* two infinities with different signs is invalid */
+ if (decNumberIsInfinite(rhs) && diffsign) {
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ bits=lhs->bits & DECNEG; /* get sign from LHS */
+ }
+ else bits=(rhs->bits^negate) & DECNEG;/* RHS must be Infinity */
+ bits|=DECINF;
+ uprv_decNumberZero(res);
+ res->bits=bits; /* set +/- infinity */
+ } /* an infinity */
+ break;
+ }
+
+ /* Quick exit for add 0s; return the non-0, modified as need be */
+ if (ISZERO(lhs)) {
+ Int adjust; /* work */
+ Int lexp=lhs->exponent; /* save in case LHS==RES */
+ bits=lhs->bits; /* .. */
+ residue=0; /* clear accumulator */
+ decCopyFit(res, rhs, set, &residue, status); /* copy (as needed) */
+ res->bits^=negate; /* flip if rhs was negated */
+ #if DECSUBSET
+ if (set->extended) { /* exponents on zeros count */
+ #endif
+ /* exponent will be the lower of the two */
+ adjust=lexp-res->exponent; /* adjustment needed [if -ve] */
+ if (ISZERO(res)) { /* both 0: special IEEE 754 rules */
+ if (adjust<0) res->exponent=lexp; /* set exponent */
+ /* 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 */
+ if (diffsign) {
+ if (set->round!=DEC_ROUND_FLOOR) res->bits=0;
+ else res->bits=DECNEG; /* preserve 0 sign */
+ }
+ }
+ else { /* non-0 res */
+ if (adjust<0) { /* 0-padding needed */
+ if ((res->digits-adjust)>set->digits) {
+ adjust=res->digits-set->digits; /* to fit exactly */
+ *status|=DEC_Rounded; /* [but exact] */
+ }
+ res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
+ res->exponent+=adjust; /* set the exponent. */
+ }
+ } /* non-0 res */
+ #if DECSUBSET
+ } /* extended */
+ #endif
+ decFinish(res, set, &residue, status); /* clean and finalize */
+ break;}
+
+ if (ISZERO(rhs)) { /* [lhs is non-zero] */
+ Int adjust; /* work */
+ Int rexp=rhs->exponent; /* save in case RHS==RES */
+ bits=rhs->bits; /* be clean */
+ residue=0; /* clear accumulator */
+ decCopyFit(res, lhs, set, &residue, status); /* copy (as needed) */
+ #if DECSUBSET
+ if (set->extended) { /* exponents on zeros count */
+ #endif
+ /* exponent will be the lower of the two */
+ /* [0-0 case handled above] */
+ adjust=rexp-res->exponent; /* adjustment needed [if -ve] */
+ if (adjust<0) { /* 0-padding needed */
+ if ((res->digits-adjust)>set->digits) {
+ adjust=res->digits-set->digits; /* to fit exactly */
+ *status|=DEC_Rounded; /* [but exact] */
+ }
+ res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
+ res->exponent+=adjust; /* set the exponent. */
+ }
+ #if DECSUBSET
+ } /* extended */
+ #endif
+ decFinish(res, set, &residue, status); /* clean and finalize */
+ break;}
+
+ /* [NB: both fastpath and mainpath code below assume these cases */
+ /* (notably 0-0) have already been handled] */
+
+ /* calculate the padding needed to align the operands */
+ padding=rhs->exponent-lhs->exponent;
+
+ /* Fastpath cases where the numbers are aligned and normal, the RHS */
+ /* is all in one unit, no operand rounding is needed, and no carry, */
+ /* lengthening, or borrow is needed */
+ if (padding==0
+ && rhs->digits<=DECDPUN
+ && rhs->exponent>=set->emin /* [some normals drop through] */
+ && rhs->exponent<=set->emax-set->digits+1 /* [could clamp] */
+ && rhs->digits<=reqdigits
+ && lhs->digits<=reqdigits) {
+ Int partial=*lhs->lsu;
+ if (!diffsign) { /* adding */
+ partial+=*rhs->lsu;
+ if ((partial<=DECDPUNMAX) /* result fits in unit */
+ && (lhs->digits>=DECDPUN || /* .. and no digits-count change */
+ partial<(Int)powers[lhs->digits])) { /* .. */
+ if (res!=lhs) uprv_decNumberCopy(res, lhs); /* not in place */
+ *res->lsu=(Unit)partial; /* [copy could have overwritten RHS] */
+ break;
+ }
+ /* else drop out for careful add */
+ }
+ else { /* signs differ */
+ partial-=*rhs->lsu;
+ if (partial>0) { /* no borrow needed, and non-0 result */
+ if (res!=lhs) uprv_decNumberCopy(res, lhs); /* not in place */
+ *res->lsu=(Unit)partial;
+ /* this could have reduced digits [but result>0] */
+ res->digits=decGetDigits(res->lsu, D2U(res->digits));
+ break;
+ }
+ /* else drop out for careful subtract */
+ }
+ }
+
+ /* Now align (pad) the lhs or rhs so they can be added or */
+ /* subtracted, as necessary. If one number is much larger than */
+ /* the other (that is, if in plain form there is a least one */
+ /* digit between the lowest digit of one and the highest of the */
+ /* other) padding with up to DIGITS-1 trailing zeros may be */
+ /* needed; then apply rounding (as exotic rounding modes may be */
+ /* affected by the residue). */
+ rhsshift=0; /* rhs shift to left (padding) in Units */
+ bits=lhs->bits; /* assume sign is that of LHS */
+ mult=1; /* likely multiplier */
+
+ /* [if padding==0 the operands are aligned; no padding is needed] */
+ if (padding!=0) {
+ /* some padding needed; always pad the RHS, as any required */
+ /* padding can then be effected by a simple combination of */
+ /* shifts and a multiply */
+ Flag swapped=0;
+ if (padding<0) { /* LHS needs the padding */
+ const decNumber *t;
+ padding=-padding; /* will be +ve */
+ bits=(uByte)(rhs->bits^negate); /* assumed sign is now that of RHS */
+ t=lhs; lhs=rhs; rhs=t;
+ swapped=1;
+ }
+
+ /* If, after pad, rhs would be longer than lhs by digits+1 or */
+ /* more then lhs cannot affect the answer, except as a residue, */
+ /* so only need to pad up to a length of DIGITS+1. */
+ if (rhs->digits+padding > lhs->digits+reqdigits+1) {
+ /* The RHS is sufficient */
+ /* for residue use the relative sign indication... */
+ Int shift=reqdigits-rhs->digits; /* left shift needed */
+ residue=1; /* residue for rounding */
+ if (diffsign) residue=-residue; /* signs differ */
+ /* copy, shortening if necessary */
+ decCopyFit(res, rhs, set, &residue, status);
+ /* if it was already shorter, then need to pad with zeros */
+ if (shift>0) {
+ res->digits=decShiftToMost(res->lsu, res->digits, shift);
+ res->exponent-=shift; /* adjust the exponent. */
+ }
+ /* flip the result sign if unswapped and rhs was negated */
+ if (!swapped) res->bits^=negate;
+ decFinish(res, set, &residue, status); /* done */
+ break;}
+
+ /* LHS digits may affect result */
+ rhsshift=D2U(padding+1)-1; /* this much by Unit shift .. */
+ mult=powers[padding-(rhsshift*DECDPUN)]; /* .. this by multiplication */
+ } /* padding needed */
+
+ if (diffsign) mult=-mult; /* signs differ */
+
+ /* determine the longer operand */
+ maxdigits=rhs->digits+padding; /* virtual length of RHS */
+ if (lhs->digits>maxdigits) maxdigits=lhs->digits;
+
+ /* Decide on the result buffer to use; if possible place directly */
+ /* into result. */
+ acc=res->lsu; /* assume add direct to result */
+ /* If destructive overlap, or the number is too long, or a carry or */
+ /* borrow to DIGITS+1 might be possible, a buffer must be used. */
+ /* [Might be worth more sophisticated tests when maxdigits==reqdigits] */
+ if ((maxdigits>=reqdigits) /* is, or could be, too large */
+ || (res==rhs && rhsshift>0)) { /* destructive overlap */
+ /* buffer needed, choose it; units for maxdigits digits will be */
+ /* needed, +1 Unit for carry or borrow */
+ Int need=D2U(maxdigits)+1;
+ acc=accbuff; /* assume use local buffer */
+ if (need*sizeof(Unit)>sizeof(accbuff)) {
+ /* printf("malloc add %ld %ld\n", need, sizeof(accbuff)); */
+ allocacc=(Unit *)malloc(need*sizeof(Unit));
+ if (allocacc==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ acc=allocacc;
+ }
+ }
+
+ res->bits=(uByte)(bits&DECNEG); /* it's now safe to overwrite.. */
+ res->exponent=lhs->exponent; /* .. operands (even if aliased) */
+
+ #if DECTRACE
+ decDumpAr('A', lhs->lsu, D2U(lhs->digits));
+ decDumpAr('B', rhs->lsu, D2U(rhs->digits));
+ printf(" :h: %ld %ld\n", rhsshift, mult);
+ #endif
+
+ /* add [A+B*m] or subtract [A+B*(-m)] */
+ res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits),
+ rhs->lsu, D2U(rhs->digits),
+ rhsshift, acc, mult)
+ *DECDPUN; /* [units -> digits] */
+ if (res->digits<0) { /* borrowed... */
+ res->digits=-res->digits;
+ res->bits^=DECNEG; /* flip the sign */
+ }
+ #if DECTRACE
+ decDumpAr('+', acc, D2U(res->digits));
+ #endif
+
+ /* If a buffer was used the result must be copied back, possibly */
+ /* shortening. (If no buffer was used then the result must have */
+ /* fit, so can't need rounding and residue must be 0.) */
+ residue=0; /* clear accumulator */
+ if (acc!=res->lsu) {
+ #if DECSUBSET
+ if (set->extended) { /* round from first significant digit */
+ #endif
+ /* remove leading zeros that were added due to rounding up to */
+ /* integral Units -- before the test for rounding. */
+ if (res->digits>reqdigits)
+ res->digits=decGetDigits(acc, D2U(res->digits));
+ decSetCoeff(res, set, acc, res->digits, &residue, status);
+ #if DECSUBSET
+ }
+ else { /* subset arithmetic rounds from original significant digit */
+ /* May have an underestimate. This only occurs when both */
+ /* numbers fit in DECDPUN digits and are padding with a */
+ /* negative multiple (-10, -100...) and the top digit(s) become */
+ /* 0. (This only matters when using X3.274 rules where the */
+ /* leading zero could be included in the rounding.) */
+ if (res->digits<maxdigits) {
+ *(acc+D2U(res->digits))=0; /* ensure leading 0 is there */
+ res->digits=maxdigits;
+ }
+ else {
+ /* remove leading zeros that added due to rounding up to */
+ /* integral Units (but only those in excess of the original */
+ /* maxdigits length, unless extended) before test for rounding. */
+ if (res->digits>reqdigits) {
+ res->digits=decGetDigits(acc, D2U(res->digits));
+ if (res->digits<maxdigits) res->digits=maxdigits;
+ }
+ }
+ decSetCoeff(res, set, acc, res->digits, &residue, status);
+ /* Now apply rounding if needed before removing leading zeros. */
+ /* This is safe because subnormals are not a possibility */
+ if (residue!=0) {
+ decApplyRound(res, set, residue, status);
+ residue=0; /* did what needed to be done */
+ }
+ } /* subset */
+ #endif
+ } /* used buffer */
+
+ /* strip leading zeros [these were left on in case of subset subtract] */
+ res->digits=decGetDigits(res->lsu, D2U(res->digits));
+
+ /* apply checks and rounding */
+ decFinish(res, set, &residue, status);
+
+ /* "When the sum of two operands with opposite signs is exactly */
+ /* zero, the sign of that sum shall be '+' in all rounding modes */
+ /* except round toward -Infinity, in which mode that sign shall be */
+ /* '-'." [Subset zeros also never have '-', set by decFinish.] */
+ if (ISZERO(res) && diffsign
+ #if DECSUBSET
+ && set->extended
+ #endif
+ && (*status&DEC_Inexact)==0) {
+ if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; /* sign - */
+ else res->bits&=~DECNEG; /* sign + */
+ }
+ } while(0); /* end protected */
+
+ if (allocacc!=NULL) free(allocacc); /* drop any storage used */
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decAddOp */
+
+/* ------------------------------------------------------------------ */
+/* decDivideOp -- division operation */
+/* */
+/* This routine performs the calculations for all four division */
+/* operators (divide, divideInteger, remainder, remainderNear). */
+/* */
+/* C=A op B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X/X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */
+/* status is the usual accumulator */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* ------------------------------------------------------------------ */
+/* The underlying algorithm of this routine is the same as in the */
+/* 1981 S/370 implementation, that is, non-restoring long division */
+/* with bi-unit (rather than bi-digit) estimation for each unit */
+/* multiplier. In this pseudocode overview, complications for the */
+/* Remainder operators and division residues for exact rounding are */
+/* omitted for clarity. */
+/* */
+/* Prepare operands and handle special values */
+/* Test for x/0 and then 0/x */
+/* Exp =Exp1 - Exp2 */
+/* Exp =Exp +len(var1) -len(var2) */
+/* Sign=Sign1 * Sign2 */
+/* Pad accumulator (Var1) to double-length with 0's (pad1) */
+/* Pad Var2 to same length as Var1 */
+/* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */
+/* have=0 */
+/* Do until (have=digits+1 OR residue=0) */
+/* if exp<0 then if integer divide/residue then leave */
+/* this_unit=0 */
+/* Do forever */
+/* compare numbers */
+/* if <0 then leave inner_loop */
+/* if =0 then (* quick exit without subtract *) do */
+/* this_unit=this_unit+1; output this_unit */
+/* leave outer_loop; end */
+/* Compare lengths of numbers (mantissae): */
+/* If same then tops2=msu2pair -- {units 1&2 of var2} */
+/* else tops2=msu2plus -- {0, unit 1 of var2} */
+/* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */
+/* mult=tops1/tops2 -- Good and safe guess at divisor */
+/* if mult=0 then mult=1 */
+/* this_unit=this_unit+mult */
+/* subtract */
+/* end inner_loop */
+/* if have\=0 | this_unit\=0 then do */
+/* output this_unit */
+/* have=have+1; end */
+/* var2=var2/10 */
+/* exp=exp-1 */
+/* end outer_loop */
+/* exp=exp+1 -- set the proper exponent */
+/* if have=0 then generate answer=0 */
+/* Return (Result is defined by Var1) */
+/* */
+/* ------------------------------------------------------------------ */
+/* Two working buffers are needed during the division; one (digits+ */
+/* 1) to accumulate the result, and the other (up to 2*digits+1) for */
+/* long subtractions. These are acc and var1 respectively. */
+/* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/
+/* The static buffers may be larger than might be expected to allow */
+/* for calls from higher-level funtions (notable exp). */
+/* ------------------------------------------------------------------ */
+static decNumber * decDivideOp(decNumber *res,
+ const decNumber *lhs, const decNumber *rhs,
+ decContext *set, Flag op, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ Unit accbuff[SD2U(DECBUFFER+DECDPUN+10)]; /* local buffer */
+ Unit *acc=accbuff; /* -> accumulator array for result */
+ Unit *allocacc=NULL; /* -> allocated buffer, iff allocated */
+ Unit *accnext; /* -> where next digit will go */
+ Int acclength; /* length of acc needed [Units] */
+ Int accunits; /* count of units accumulated */
+ Int accdigits; /* count of digits accumulated */
+
+ Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)]; /* buffer for var1 */
+ Unit *var1=varbuff; /* -> var1 array for long subtraction */
+ Unit *varalloc=NULL; /* -> allocated buffer, iff used */
+ Unit *msu1; /* -> msu of var1 */
+
+ const Unit *var2; /* -> var2 array */
+ const Unit *msu2; /* -> msu of var2 */
+ Int msu2plus; /* msu2 plus one [does not vary] */
+ eInt msu2pair; /* msu2 pair plus one [does not vary] */
+
+ Int var1units, var2units; /* actual lengths */
+ Int var2ulen; /* logical length (units) */
+ Int var1initpad=0; /* var1 initial padding (digits) */
+ Int maxdigits; /* longest LHS or required acc length */
+ Int mult; /* multiplier for subtraction */
+ Unit thisunit; /* current unit being accumulated */
+ Int residue; /* for rounding */
+ Int reqdigits=set->digits; /* requested DIGITS */
+ Int exponent; /* working exponent */
+ Int maxexponent=0; /* DIVIDE maximum exponent if unrounded */
+ uByte bits; /* working sign */
+ Unit *target; /* work */
+ const Unit *source; /* .. */
+ uInt const *pow; /* .. */
+ Int shift, cut; /* .. */
+ #if DECSUBSET
+ Int dropped; /* work */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ bits=(lhs->bits^rhs->bits)&DECNEG; /* assumed sign for divisions */
+
+ /* handle infinities and NaNs */
+ if (SPECIALARGS) { /* a special bit set */
+ if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
+ decNaNs(res, lhs, rhs, set, status);
+ break;
+ }
+ /* one or two infinities */
+ if (decNumberIsInfinite(lhs)) { /* LHS (dividend) is infinite */
+ if (decNumberIsInfinite(rhs) || /* two infinities are invalid .. */
+ op & (REMAINDER | REMNEAR)) { /* as is remainder of infinity */
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ /* [Note that infinity/0 raises no exceptions] */
+ uprv_decNumberZero(res);
+ res->bits=bits|DECINF; /* set +/- infinity */
+ break;
+ }
+ else { /* RHS (divisor) is infinite */
+ residue=0;
+ if (op&(REMAINDER|REMNEAR)) {
+ /* result is [finished clone of] lhs */
+ decCopyFit(res, lhs, set, &residue, status);
+ }
+ else { /* a division */
+ uprv_decNumberZero(res);
+ res->bits=bits; /* set +/- zero */
+ /* for DIVIDEINT the exponent is always 0. For DIVIDE, result */
+ /* is a 0 with infinitely negative exponent, clamped to minimum */
+ if (op&DIVIDE) {
+ res->exponent=set->emin-set->digits+1;
+ *status|=DEC_Clamped;
+ }
+ }
+ decFinish(res, set, &residue, status);
+ break;
+ }
+ }
+
+ /* handle 0 rhs (x/0) */
+ if (ISZERO(rhs)) { /* x/0 is always exceptional */
+ if (ISZERO(lhs)) {
+ uprv_decNumberZero(res); /* [after lhs test] */
+ *status|=DEC_Division_undefined;/* 0/0 will become NaN */
+ }
+ else {
+ uprv_decNumberZero(res);
+ if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation;
+ else {
+ *status|=DEC_Division_by_zero; /* x/0 */
+ res->bits=bits|DECINF; /* .. is +/- Infinity */
+ }
+ }
+ break;}
+
+ /* handle 0 lhs (0/x) */
+ if (ISZERO(lhs)) { /* 0/x [x!=0] */
+ #if DECSUBSET
+ if (!set->extended) uprv_decNumberZero(res);
+ else {
+ #endif
+ if (op&DIVIDE) {
+ residue=0;
+ exponent=lhs->exponent-rhs->exponent; /* ideal exponent */
+ uprv_decNumberCopy(res, lhs); /* [zeros always fit] */
+ res->bits=bits; /* sign as computed */
+ res->exponent=exponent; /* exponent, too */
+ decFinalize(res, set, &residue, status); /* check exponent */
+ }
+ else if (op&DIVIDEINT) {
+ uprv_decNumberZero(res); /* integer 0 */
+ res->bits=bits; /* sign as computed */
+ }
+ else { /* a remainder */
+ exponent=rhs->exponent; /* [save in case overwrite] */
+ uprv_decNumberCopy(res, lhs); /* [zeros always fit] */
+ if (exponent<res->exponent) res->exponent=exponent; /* use lower */
+ }
+ #if DECSUBSET
+ }
+ #endif
+ break;}
+
+ /* Precalculate exponent. This starts off adjusted (and hence fits */
+ /* in 31 bits) and becomes the usual unadjusted exponent as the */
+ /* division proceeds. The order of evaluation is important, here, */
+ /* to avoid wrap. */
+ exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits);
+
+ /* If the working exponent is -ve, then some quick exits are */
+ /* possible because the quotient is known to be <1 */
+ /* [for REMNEAR, it needs to be < -1, as -0.5 could need work] */
+ if (exponent<0 && !(op==DIVIDE)) {
+ if (op&DIVIDEINT) {
+ uprv_decNumberZero(res); /* integer part is 0 */
+ #if DECSUBSET
+ if (set->extended)
+ #endif
+ res->bits=bits; /* set +/- zero */
+ break;}
+ /* fastpath remainders so long as the lhs has the smaller */
+ /* (or equal) exponent */
+ if (lhs->exponent<=rhs->exponent) {
+ if (op&REMAINDER || exponent<-1) {
+ /* It is REMAINDER or safe REMNEAR; result is [finished */
+ /* clone of] lhs (r = x - 0*y) */
+ residue=0;
+ decCopyFit(res, lhs, set, &residue, status);
+ decFinish(res, set, &residue, status);
+ break;
+ }
+ /* [unsafe REMNEAR drops through] */
+ }
+ } /* fastpaths */
+
+ /* Long (slow) division is needed; roll up the sleeves... */
+
+ /* The accumulator will hold the quotient of the division. */
+ /* If it needs to be too long for stack storage, then allocate. */
+ acclength=D2U(reqdigits+DECDPUN); /* in Units */
+ if (acclength*sizeof(Unit)>sizeof(accbuff)) {
+ /* printf("malloc dvacc %ld units\n", acclength); */
+ allocacc=(Unit *)malloc(acclength*sizeof(Unit));
+ if (allocacc==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ acc=allocacc; /* use the allocated space */
+ }
+
+ /* var1 is the padded LHS ready for subtractions. */
+ /* If it needs to be too long for stack storage, then allocate. */
+ /* The maximum units needed for var1 (long subtraction) is: */
+ /* Enough for */
+ /* (rhs->digits+reqdigits-1) -- to allow full slide to right */
+ /* or (lhs->digits) -- to allow for long lhs */
+ /* whichever is larger */
+ /* +1 -- for rounding of slide to right */
+ /* +1 -- for leading 0s */
+ /* +1 -- for pre-adjust if a remainder or DIVIDEINT */
+ /* [Note: unused units do not participate in decUnitAddSub data] */
+ maxdigits=rhs->digits+reqdigits-1;
+ if (lhs->digits>maxdigits) maxdigits=lhs->digits;
+ var1units=D2U(maxdigits)+2;
+ /* allocate a guard unit above msu1 for REMAINDERNEAR */
+ if (!(op&DIVIDE)) var1units++;
+ if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) {
+ /* printf("malloc dvvar %ld units\n", var1units+1); */
+ varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit));
+ if (varalloc==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ var1=varalloc; /* use the allocated space */
+ }
+
+ /* Extend the lhs and rhs to full long subtraction length. The lhs */
+ /* is truly extended into the var1 buffer, with 0 padding, so a */
+ /* subtract in place is always possible. The rhs (var2) has */
+ /* virtual padding (implemented by decUnitAddSub). */
+ /* One guard unit was allocated above msu1 for rem=rem+rem in */
+ /* REMAINDERNEAR. */
+ msu1=var1+var1units-1; /* msu of var1 */
+ source=lhs->lsu+D2U(lhs->digits)-1; /* msu of input array */
+ for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source;
+ for (; target>=var1; target--) *target=0;
+
+ /* rhs (var2) is left-aligned with var1 at the start */
+ var2ulen=var1units; /* rhs logical length (units) */
+ var2units=D2U(rhs->digits); /* rhs actual length (units) */
+ var2=rhs->lsu; /* -> rhs array */
+ msu2=var2+var2units-1; /* -> msu of var2 [never changes] */
+ /* now set up the variables which will be used for estimating the */
+ /* multiplication factor. If these variables are not exact, add */
+ /* 1 to make sure that the multiplier is never overestimated. */
+ msu2plus=*msu2; /* it's value .. */
+ if (var2units>1) msu2plus++; /* .. +1 if any more */
+ msu2pair=(eInt)*msu2*(DECDPUNMAX+1);/* top two pair .. */
+ if (var2units>1) { /* .. [else treat 2nd as 0] */
+ msu2pair+=*(msu2-1); /* .. */
+ if (var2units>2) msu2pair++; /* .. +1 if any more */
+ }
+
+ /* The calculation is working in units, which may have leading zeros, */
+ /* but the exponent was calculated on the assumption that they are */
+ /* both left-aligned. Adjust the exponent to compensate: add the */
+ /* number of leading zeros in var1 msu and subtract those in var2 msu. */
+ /* [This is actually done by counting the digits and negating, as */
+ /* lead1=DECDPUN-digits1, and similarly for lead2.] */
+ for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--;
+ for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++;
+
+ /* Now, if doing an integer divide or remainder, ensure that */
+ /* the result will be Unit-aligned. To do this, shift the var1 */
+ /* accumulator towards least if need be. (It's much easier to */
+ /* do this now than to reassemble the residue afterwards, if */
+ /* doing a remainder.) Also ensure the exponent is not negative. */
+ if (!(op&DIVIDE)) {
+ Unit *u; /* work */
+ /* save the initial 'false' padding of var1, in digits */
+ var1initpad=(var1units-D2U(lhs->digits))*DECDPUN;
+ /* Determine the shift to do. */
+ if (exponent<0) cut=-exponent;
+ else cut=DECDPUN-exponent%DECDPUN;
+ decShiftToLeast(var1, var1units, cut);
+ exponent+=cut; /* maintain numerical value */
+ var1initpad-=cut; /* .. and reduce padding */
+ /* clean any most-significant units which were just emptied */
+ for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0;
+ } /* align */
+ else { /* is DIVIDE */
+ maxexponent=lhs->exponent-rhs->exponent; /* save */
+ /* optimization: if the first iteration will just produce 0, */
+ /* preadjust to skip it [valid for DIVIDE only] */
+ if (*msu1<*msu2) {
+ var2ulen--; /* shift down */
+ exponent-=DECDPUN; /* update the exponent */
+ }
+ }
+
+ /* ---- start the long-division loops ------------------------------ */
+ accunits=0; /* no units accumulated yet */
+ accdigits=0; /* .. or digits */
+ accnext=acc+acclength-1; /* -> msu of acc [NB: allows digits+1] */
+ for (;;) { /* outer forever loop */
+ thisunit=0; /* current unit assumed 0 */
+ /* find the next unit */
+ for (;;) { /* inner forever loop */
+ /* strip leading zero units [from either pre-adjust or from */
+ /* subtract last time around]. Leave at least one unit. */
+ for (; *msu1==0 && msu1>var1; msu1--) var1units--;
+
+ if (var1units<var2ulen) break; /* var1 too low for subtract */
+ if (var1units==var2ulen) { /* unit-by-unit compare needed */
+ /* compare the two numbers, from msu */
+ const Unit *pv1, *pv2;
+ Unit v2; /* units to compare */
+ pv2=msu2; /* -> msu */
+ for (pv1=msu1; ; pv1--, pv2--) {
+ /* v1=*pv1 -- always OK */
+ v2=0; /* assume in padding */
+ if (pv2>=var2) v2=*pv2; /* in range */
+ if (*pv1!=v2) break; /* no longer the same */
+ if (pv1==var1) break; /* done; leave pv1 as is */
+ }
+ /* here when all inspected or a difference seen */
+ if (*pv1<v2) break; /* var1 too low to subtract */
+ if (*pv1==v2) { /* var1 == var2 */
+ /* reach here if var1 and var2 are identical; subtraction */
+ /* would increase digit by one, and the residue will be 0 so */
+ /* the calculation is done; leave the loop with residue=0. */
+ thisunit++; /* as though subtracted */
+ *var1=0; /* set var1 to 0 */
+ var1units=1; /* .. */
+ break; /* from inner */
+ } /* var1 == var2 */
+ /* *pv1>v2. Prepare for real subtraction; the lengths are equal */
+ /* Estimate the multiplier (there's always a msu1-1)... */
+ /* Bring in two units of var2 to provide a good estimate. */
+ mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair);
+ } /* lengths the same */
+ else { /* var1units > var2ulen, so subtraction is safe */
+ /* The var2 msu is one unit towards the lsu of the var1 msu, */
+ /* so only one unit for var2 can be used. */
+ mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus);
+ }
+ if (mult==0) mult=1; /* must always be at least 1 */
+ /* subtraction needed; var1 is > var2 */
+ thisunit=(Unit)(thisunit+mult); /* accumulate */
+ /* subtract var1-var2, into var1; only the overlap needs */
+ /* processing, as this is an in-place calculation */
+ shift=var2ulen-var2units;
+ #if DECTRACE
+ decDumpAr('1', &var1[shift], var1units-shift);
+ decDumpAr('2', var2, var2units);
+ printf("m=%ld\n", -mult);
+ #endif
+ decUnitAddSub(&var1[shift], var1units-shift,
+ var2, var2units, 0,
+ &var1[shift], -mult);
+ #if DECTRACE
+ decDumpAr('#', &var1[shift], var1units-shift);
+ #endif
+ /* var1 now probably has leading zeros; these are removed at the */
+ /* top of the inner loop. */
+ } /* inner loop */
+
+ /* The next unit has been calculated in full; unless it's a */
+ /* leading zero, add to acc */
+ if (accunits!=0 || thisunit!=0) { /* is first or non-zero */
+ *accnext=thisunit; /* store in accumulator */
+ /* account exactly for the new digits */
+ if (accunits==0) {
+ accdigits++; /* at least one */
+ for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++;
+ }
+ else accdigits+=DECDPUN;
+ accunits++; /* update count */
+ accnext--; /* ready for next */
+ if (accdigits>reqdigits) break; /* have enough digits */
+ }
+
+ /* if the residue is zero, the operation is done (unless divide */
+ /* or divideInteger and still not enough digits yet) */
+ if (*var1==0 && var1units==1) { /* residue is 0 */
+ if (op&(REMAINDER|REMNEAR)) break;
+ if ((op&DIVIDE) && (exponent<=maxexponent)) break;
+ /* [drop through if divideInteger] */
+ }
+ /* also done enough if calculating remainder or integer */
+ /* divide and just did the last ('units') unit */
+ if (exponent==0 && !(op&DIVIDE)) break;
+
+ /* to get here, var1 is less than var2, so divide var2 by the per- */
+ /* Unit power of ten and go for the next digit */
+ var2ulen--; /* shift down */
+ exponent-=DECDPUN; /* update the exponent */
+ } /* outer loop */
+
+ /* ---- division is complete --------------------------------------- */
+ /* here: acc has at least reqdigits+1 of good results (or fewer */
+ /* if early stop), starting at accnext+1 (its lsu) */
+ /* var1 has any residue at the stopping point */
+ /* accunits is the number of digits collected in acc */
+ if (accunits==0) { /* acc is 0 */
+ accunits=1; /* show have a unit .. */
+ accdigits=1; /* .. */
+ *accnext=0; /* .. whose value is 0 */
+ }
+ else accnext++; /* back to last placed */
+ /* accnext now -> lowest unit of result */
+
+ residue=0; /* assume no residue */
+ if (op&DIVIDE) {
+ /* record the presence of any residue, for rounding */
+ if (*var1!=0 || var1units>1) residue=1;
+ else { /* no residue */
+ /* Had an exact division; clean up spurious trailing 0s. */
+ /* There will be at most DECDPUN-1, from the final multiply, */
+ /* and then only if the result is non-0 (and even) and the */
+ /* exponent is 'loose'. */
+ #if DECDPUN>1
+ Unit lsu=*accnext;
+ if (!(lsu&0x01) && (lsu!=0)) {
+ /* count the trailing zeros */
+ Int drop=0;
+ for (;; drop++) { /* [will terminate because lsu!=0] */
+ if (exponent>=maxexponent) break; /* don't chop real 0s */
+ #if DECDPUN<=4
+ if ((lsu-QUOT10(lsu, drop+1)
+ *powers[drop+1])!=0) break; /* found non-0 digit */
+ #else
+ if (lsu%powers[drop+1]!=0) break; /* found non-0 digit */
+ #endif
+ exponent++;
+ }
+ if (drop>0) {
+ accunits=decShiftToLeast(accnext, accunits, drop);
+ accdigits=decGetDigits(accnext, accunits);
+ accunits=D2U(accdigits);
+ /* [exponent was adjusted in the loop] */
+ }
+ } /* neither odd nor 0 */
+ #endif
+ } /* exact divide */
+ } /* divide */
+ else /* op!=DIVIDE */ {
+ /* check for coefficient overflow */
+ if (accdigits+exponent>reqdigits) {
+ *status|=DEC_Division_impossible;
+ break;
+ }
+ if (op & (REMAINDER|REMNEAR)) {
+ /* [Here, the exponent will be 0, because var1 was adjusted */
+ /* appropriately.] */
+ Int postshift; /* work */
+ Flag wasodd=0; /* integer was odd */
+ Unit *quotlsu; /* for save */
+ Int quotdigits; /* .. */
+
+ bits=lhs->bits; /* remainder sign is always as lhs */
+
+ /* Fastpath when residue is truly 0 is worthwhile [and */
+ /* simplifies the code below] */
+ if (*var1==0 && var1units==1) { /* residue is 0 */
+ Int exp=lhs->exponent; /* save min(exponents) */
+ if (rhs->exponent<exp) exp=rhs->exponent;
+ uprv_decNumberZero(res); /* 0 coefficient */
+ #if DECSUBSET
+ if (set->extended)
+ #endif
+ res->exponent=exp; /* .. with proper exponent */
+ res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
+ decFinish(res, set, &residue, status); /* might clamp */
+ break;
+ }
+ /* note if the quotient was odd */
+ if (*accnext & 0x01) wasodd=1; /* acc is odd */
+ quotlsu=accnext; /* save in case need to reinspect */
+ quotdigits=accdigits; /* .. */
+
+ /* treat the residue, in var1, as the value to return, via acc */
+ /* calculate the unused zero digits. This is the smaller of: */
+ /* var1 initial padding (saved above) */
+ /* var2 residual padding, which happens to be given by: */
+ postshift=var1initpad+exponent-lhs->exponent+rhs->exponent;
+ /* [the 'exponent' term accounts for the shifts during divide] */
+ if (var1initpad<postshift) postshift=var1initpad;
+
+ /* shift var1 the requested amount, and adjust its digits */
+ var1units=decShiftToLeast(var1, var1units, postshift);
+ accnext=var1;
+ accdigits=decGetDigits(var1, var1units);
+ accunits=D2U(accdigits);
+
+ exponent=lhs->exponent; /* exponent is smaller of lhs & rhs */
+ if (rhs->exponent<exponent) exponent=rhs->exponent;
+
+ /* Now correct the result if doing remainderNear; if it */
+ /* (looking just at coefficients) is > rhs/2, or == rhs/2 and */
+ /* the integer was odd then the result should be rem-rhs. */
+ if (op&REMNEAR) {
+ Int compare, tarunits; /* work */
+ Unit *up; /* .. */
+ /* calculate remainder*2 into the var1 buffer (which has */
+ /* 'headroom' of an extra unit and hence enough space) */
+ /* [a dedicated 'double' loop would be faster, here] */
+ tarunits=decUnitAddSub(accnext, accunits, accnext, accunits,
+ 0, accnext, 1);
+ /* decDumpAr('r', accnext, tarunits); */
+
+ /* Here, accnext (var1) holds tarunits Units with twice the */
+ /* remainder's coefficient, which must now be compared to the */
+ /* RHS. The remainder's exponent may be smaller than the RHS's. */
+ compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits),
+ rhs->exponent-exponent);
+ if (compare==BADINT) { /* deep trouble */
+ *status|=DEC_Insufficient_storage;
+ break;}
+
+ /* now restore the remainder by dividing by two; the lsu */
+ /* is known to be even. */
+ for (up=accnext; up<accnext+tarunits; up++) {
+ Int half; /* half to add to lower unit */
+ half=*up & 0x01;
+ *up/=2; /* [shift] */
+ if (!half) continue;
+ *(up-1)+=(DECDPUNMAX+1)/2;
+ }
+ /* [accunits still describes the original remainder length] */
+
+ if (compare>0 || (compare==0 && wasodd)) { /* adjustment needed */
+ Int exp, expunits, exprem; /* work */
+ /* This is effectively causing round-up of the quotient, */
+ /* so if it was the rare case where it was full and all */
+ /* nines, it would overflow and hence division-impossible */
+ /* should be raised */
+ Flag allnines=0; /* 1 if quotient all nines */
+ if (quotdigits==reqdigits) { /* could be borderline */
+ for (up=quotlsu; ; up++) {
+ if (quotdigits>DECDPUN) {
+ if (*up!=DECDPUNMAX) break;/* non-nines */
+ }
+ else { /* this is the last Unit */
+ if (*up==powers[quotdigits]-1) allnines=1;
+ break;
+ }
+ quotdigits-=DECDPUN; /* checked those digits */
+ } /* up */
+ } /* borderline check */
+ if (allnines) {
+ *status|=DEC_Division_impossible;
+ break;}
+
+ /* rem-rhs is needed; the sign will invert. Again, var1 */
+ /* can safely be used for the working Units array. */
+ exp=rhs->exponent-exponent; /* RHS padding needed */
+ /* Calculate units and remainder from exponent. */
+ expunits=exp/DECDPUN;
+ exprem=exp%DECDPUN;
+ /* subtract [A+B*(-m)]; the result will always be negative */
+ accunits=-decUnitAddSub(accnext, accunits,
+ rhs->lsu, D2U(rhs->digits),
+ expunits, accnext, -(Int)powers[exprem]);
+ accdigits=decGetDigits(accnext, accunits); /* count digits exactly */
+ accunits=D2U(accdigits); /* and recalculate the units for copy */
+ /* [exponent is as for original remainder] */
+ bits^=DECNEG; /* flip the sign */
+ }
+ } /* REMNEAR */
+ } /* REMAINDER or REMNEAR */
+ } /* not DIVIDE */
+
+ /* Set exponent and bits */
+ res->exponent=exponent;
+ res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
+
+ /* Now the coefficient. */
+ decSetCoeff(res, set, accnext, accdigits, &residue, status);
+
+ decFinish(res, set, &residue, status); /* final cleanup */
+
+ #if DECSUBSET
+ /* If a divide then strip trailing zeros if subset [after round] */
+ if (!set->extended && (op==DIVIDE)) decTrim(res, set, 0, 1, &dropped);
+ #endif
+ } while(0); /* end protected */
+
+ if (varalloc!=NULL) free(varalloc); /* drop any storage used */
+ if (allocacc!=NULL) free(allocacc); /* .. */
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decDivideOp */
+
+/* ------------------------------------------------------------------ */
+/* decMultiplyOp -- multiplication operation */
+/* */
+/* This routine performs the multiplication C=A x B. */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X*X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* status is the usual accumulator */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* ------------------------------------------------------------------ */
+/* 'Classic' multiplication is used rather than Karatsuba, as the */
+/* latter would give only a minor improvement for the short numbers */
+/* expected to be handled most (and uses much more memory). */
+/* */
+/* There are two major paths here: the general-purpose ('old code') */
+/* path which handles all DECDPUN values, and a fastpath version */
+/* which is used if 64-bit ints are available, DECDPUN<=4, and more */
+/* than two calls to decUnitAddSub would be made. */
+/* */
+/* The fastpath version lumps units together into 8-digit or 9-digit */
+/* chunks, and also uses a lazy carry strategy to minimise expensive */
+/* 64-bit divisions. The chunks are then broken apart again into */
+/* units for continuing processing. Despite this overhead, the */
+/* fastpath can speed up some 16-digit operations by 10x (and much */
+/* more for higher-precision calculations). */
+/* */
+/* A buffer always has to be used for the accumulator; in the */
+/* fastpath, buffers are also always needed for the chunked copies of */
+/* of the operand coefficients. */
+/* Static buffers are larger than needed just for multiply, to allow */
+/* for calls from other operations (notably exp). */
+/* ------------------------------------------------------------------ */
+#define FASTMUL (DECUSE64 && DECDPUN<5)
+static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ uInt *status) {
+ Int accunits; /* Units of accumulator in use */
+ Int exponent; /* work */
+ Int residue=0; /* rounding residue */
+ uByte bits; /* result sign */
+ Unit *acc; /* -> accumulator Unit array */
+ Int needbytes; /* size calculator */
+ void *allocacc=NULL; /* -> allocated accumulator, iff allocated */
+ Unit accbuff[SD2U(DECBUFFER*4+1)]; /* buffer (+1 for DECBUFFER==0, */
+ /* *4 for calls from other operations) */
+ const Unit *mer, *mermsup; /* work */
+ Int madlength; /* Units in multiplicand */
+ Int shift; /* Units to shift multiplicand by */
+
+ #if FASTMUL
+ /* if DECDPUN is 1 or 3 work in base 10**9, otherwise */
+ /* (DECDPUN is 2 or 4) then work in base 10**8 */
+ #if DECDPUN & 1 /* odd */
+ #define FASTBASE 1000000000 /* base */
+ #define FASTDIGS 9 /* digits in base */
+ #define FASTLAZY 18 /* carry resolution point [1->18] */
+ #else
+ #define FASTBASE 100000000
+ #define FASTDIGS 8
+ #define FASTLAZY 1844 /* carry resolution point [1->1844] */
+ #endif
+ /* three buffers are used, two for chunked copies of the operands */
+ /* (base 10**8 or base 10**9) and one base 2**64 accumulator with */
+ /* lazy carry evaluation */
+ uInt zlhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
+ uInt *zlhi=zlhibuff; /* -> lhs array */
+ uInt *alloclhi=NULL; /* -> allocated buffer, iff allocated */
+ uInt zrhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
+ uInt *zrhi=zrhibuff; /* -> rhs array */
+ uInt *allocrhi=NULL; /* -> allocated buffer, iff allocated */
+ uLong zaccbuff[(DECBUFFER*2+1)/4+2]; /* buffer (+1 for DECBUFFER==0) */
+ /* [allocacc is shared for both paths, as only one will run] */
+ uLong *zacc=zaccbuff; /* -> accumulator array for exact result */
+ #if DECDPUN==1
+ Int zoff; /* accumulator offset */
+ #endif
+ uInt *lip, *rip; /* item pointers */
+ uInt *lmsi, *rmsi; /* most significant items */
+ Int ilhs, irhs, iacc; /* item counts in the arrays */
+ Int lazy; /* lazy carry counter */
+ uLong lcarry; /* uLong carry */
+ uInt carry; /* carry (NB not uLong) */
+ Int count; /* work */
+ const Unit *cup; /* .. */
+ Unit *up; /* .. */
+ uLong *lp; /* .. */
+ Int p; /* .. */
+ #endif
+
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* -> allocated buffer, iff allocated */
+ decNumber *allocrhs=NULL; /* -> allocated buffer, iff allocated */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* precalculate result sign */
+ bits=(uByte)((lhs->bits^rhs->bits)&DECNEG);
+
+ /* handle infinities and NaNs */
+ if (SPECIALARGS) { /* a special bit set */
+ if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
+ decNaNs(res, lhs, rhs, set, status);
+ return res;}
+ /* one or two infinities; Infinity * 0 is invalid */
+ if (((lhs->bits & DECINF)==0 && ISZERO(lhs))
+ ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) {
+ *status|=DEC_Invalid_operation;
+ return res;}
+ uprv_decNumberZero(res);
+ res->bits=bits|DECINF; /* infinity */
+ return res;}
+
+ /* For best speed, as in DMSRCN [the original Rexx numerics */
+ /* module], use the shorter number as the multiplier (rhs) and */
+ /* the longer as the multiplicand (lhs) to minimise the number of */
+ /* adds (partial products) */
+ if (lhs->digits<rhs->digits) { /* swap... */
+ const decNumber *hold=lhs;
+ lhs=rhs;
+ rhs=hold;
+ }
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>set->digits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ #if FASTMUL /* fastpath can be used */
+ /* use the fast path if there are enough digits in the shorter */
+ /* operand to make the setup and takedown worthwhile */
+ #define NEEDTWO (DECDPUN*2) /* within two decUnitAddSub calls */
+ if (rhs->digits>NEEDTWO) { /* use fastpath... */
+ /* calculate the number of elements in each array */
+ ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; /* [ceiling] */
+ irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; /* .. */
+ iacc=ilhs+irhs;
+
+ /* allocate buffers if required, as usual */
+ needbytes=ilhs*sizeof(uInt);
+ if (needbytes>(Int)sizeof(zlhibuff)) {
+ alloclhi=(uInt *)malloc(needbytes);
+ zlhi=alloclhi;}
+ needbytes=irhs*sizeof(uInt);
+ if (needbytes>(Int)sizeof(zrhibuff)) {
+ allocrhi=(uInt *)malloc(needbytes);
+ zrhi=allocrhi;}
+
+ /* Allocating the accumulator space needs a special case when */
+ /* DECDPUN=1 because when converting the accumulator to Units */
+ /* after the multiplication each 8-byte item becomes 9 1-byte */
+ /* units. Therefore iacc extra bytes are needed at the front */
+ /* (rounded up to a multiple of 8 bytes), and the uLong */
+ /* accumulator starts offset the appropriate number of units */
+ /* to the right to avoid overwrite during the unchunking. */
+ needbytes=iacc*sizeof(uLong);
+ #if DECDPUN==1
+ zoff=(iacc+7)/8; /* items to offset by */
+ needbytes+=zoff*8;
+ #endif
+ if (needbytes>(Int)sizeof(zaccbuff)) {
+ allocacc=(uLong *)malloc(needbytes);
+ zacc=(uLong *)allocacc;}
+ if (zlhi==NULL||zrhi==NULL||zacc==NULL) {
+ *status|=DEC_Insufficient_storage;
+ break;}
+
+ acc=(Unit *)zacc; /* -> target Unit array */
+ #if DECDPUN==1
+ zacc+=zoff; /* start uLong accumulator to right */
+ #endif
+
+ /* assemble the chunked copies of the left and right sides */
+ for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++)
+ for (p=0, *lip=0; p<FASTDIGS && count>0;
+ p+=DECDPUN, cup++, count-=DECDPUN)
+ *lip+=*cup*powers[p];
+ lmsi=lip-1; /* save -> msi */
+ for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++)
+ for (p=0, *rip=0; p<FASTDIGS && count>0;
+ p+=DECDPUN, cup++, count-=DECDPUN)
+ *rip+=*cup*powers[p];
+ rmsi=rip-1; /* save -> msi */
+
+ /* zero the accumulator */
+ for (lp=zacc; lp<zacc+iacc; lp++) *lp=0;
+
+ /* Start the multiplication */
+ /* Resolving carries can dominate the cost of accumulating the */
+ /* partial products, so this is only done when necessary. */
+ /* Each uLong item in the accumulator can hold values up to */
+ /* 2**64-1, and each partial product can be as large as */
+ /* (10**FASTDIGS-1)**2. When FASTDIGS=9, this can be added to */
+ /* itself 18.4 times in a uLong without overflowing, so during */
+ /* the main calculation resolution is carried out every 18th */
+ /* add -- every 162 digits. Similarly, when FASTDIGS=8, the */
+ /* partial products can be added to themselves 1844.6 times in */
+ /* a uLong without overflowing, so intermediate carry */
+ /* resolution occurs only every 14752 digits. Hence for common */
+ /* short numbers usually only the one final carry resolution */
+ /* occurs. */
+ /* (The count is set via FASTLAZY to simplify experiments to */
+ /* measure the value of this approach: a 35% improvement on a */
+ /* [34x34] multiply.) */
+ lazy=FASTLAZY; /* carry delay count */
+ for (rip=zrhi; rip<=rmsi; rip++) { /* over each item in rhs */
+ lp=zacc+(rip-zrhi); /* where to add the lhs */
+ for (lip=zlhi; lip<=lmsi; lip++, lp++) { /* over each item in lhs */
+ *lp+=(uLong)(*lip)*(*rip); /* [this should in-line] */
+ } /* lip loop */
+ lazy--;
+ if (lazy>0 && rip!=rmsi) continue;
+ lazy=FASTLAZY; /* reset delay count */
+ /* spin up the accumulator resolving overflows */
+ for (lp=zacc; lp<zacc+iacc; lp++) {
+ if (*lp<FASTBASE) continue; /* it fits */
+ lcarry=*lp/FASTBASE; /* top part [slow divide] */
+ /* lcarry can exceed 2**32-1, so check again; this check */
+ /* and occasional extra divide (slow) is well worth it, as */
+ /* it allows FASTLAZY to be increased to 18 rather than 4 */
+ /* in the FASTDIGS=9 case */
+ if (lcarry<FASTBASE) carry=(uInt)lcarry; /* [usual] */
+ else { /* two-place carry [fairly rare] */
+ uInt carry2=(uInt)(lcarry/FASTBASE); /* top top part */
+ *(lp+2)+=carry2; /* add to item+2 */
+ *lp-=((uLong)FASTBASE*FASTBASE*carry2); /* [slow] */
+ carry=(uInt)(lcarry-((uLong)FASTBASE*carry2)); /* [inline] */
+ }
+ *(lp+1)+=carry; /* add to item above [inline] */
+ *lp-=((uLong)FASTBASE*carry); /* [inline] */
+ } /* carry resolution */
+ } /* rip loop */
+
+ /* The multiplication is complete; time to convert back into */
+ /* units. This can be done in-place in the accumulator and in */
+ /* 32-bit operations, because carries were resolved after the */
+ /* final add. This needs N-1 divides and multiplies for */
+ /* each item in the accumulator (which will become up to N */
+ /* units, where 2<=N<=9). */
+ for (lp=zacc, up=acc; lp<zacc+iacc; lp++) {
+ uInt item=(uInt)*lp; /* decapitate to uInt */
+ for (p=0; p<FASTDIGS-DECDPUN; p+=DECDPUN, up++) {
+ uInt part=item/(DECDPUNMAX+1);
+ *up=(Unit)(item-(part*(DECDPUNMAX+1)));
+ item=part;
+ } /* p */
+ *up=(Unit)item; up++; /* [final needs no division] */
+ } /* lp */
+ accunits=up-acc; /* count of units */
+ }
+ else { /* here to use units directly, without chunking ['old code'] */
+ #endif
+
+ /* if accumulator will be too long for local storage, then allocate */
+ acc=accbuff; /* -> assume buffer for accumulator */
+ needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit);
+ if (needbytes>(Int)sizeof(accbuff)) {
+ allocacc=(Unit *)malloc(needbytes);
+ if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;}
+ acc=(Unit *)allocacc; /* use the allocated space */
+ }
+
+ /* Now the main long multiplication loop */
+ /* Unlike the equivalent in the IBM Java implementation, there */
+ /* is no advantage in calculating from msu to lsu. So, do it */
+ /* by the book, as it were. */
+ /* Each iteration calculates ACC=ACC+MULTAND*MULT */
+ accunits=1; /* accumulator starts at '0' */
+ *acc=0; /* .. (lsu=0) */
+ shift=0; /* no multiplicand shift at first */
+ madlength=D2U(lhs->digits); /* this won't change */
+ mermsup=rhs->lsu+D2U(rhs->digits); /* -> msu+1 of multiplier */
+
+ for (mer=rhs->lsu; mer<mermsup; mer++) {
+ /* Here, *mer is the next Unit in the multiplier to use */
+ /* If non-zero [optimization] add it... */
+ if (*mer!=0) accunits=decUnitAddSub(&acc[shift], accunits-shift,
+ lhs->lsu, madlength, 0,
+ &acc[shift], *mer)
+ + shift;
+ else { /* extend acc with a 0; it will be used shortly */
+ *(acc+accunits)=0; /* [this avoids length of <=0 later] */
+ accunits++;
+ }
+ /* multiply multiplicand by 10**DECDPUN for next Unit to left */
+ shift++; /* add this for 'logical length' */
+ } /* n */
+ #if FASTMUL
+ } /* unchunked units */
+ #endif
+ /* common end-path */
+ #if DECTRACE
+ decDumpAr('*', acc, accunits); /* Show exact result */
+ #endif
+
+ /* acc now contains the exact result of the multiplication, */
+ /* possibly with a leading zero unit; build the decNumber from */
+ /* it, noting if any residue */
+ res->bits=bits; /* set sign */
+ res->digits=decGetDigits(acc, accunits); /* count digits exactly */
+
+ /* There can be a 31-bit wrap in calculating the exponent. */
+ /* This can only happen if both input exponents are negative and */
+ /* both their magnitudes are large. If there was a wrap, set a */
+ /* safe very negative exponent, from which decFinalize() will */
+ /* raise a hard underflow shortly. */
+ exponent=lhs->exponent+rhs->exponent; /* calculate exponent */
+ if (lhs->exponent<0 && rhs->exponent<0 && exponent>0)
+ exponent=-2*DECNUMMAXE; /* force underflow */
+ res->exponent=exponent; /* OK to overwrite now */
+
+
+ /* Set the coefficient. If any rounding, residue records */
+ decSetCoeff(res, set, acc, res->digits, &residue, status);
+ decFinish(res, set, &residue, status); /* final cleanup */
+ } while(0); /* end protected */
+
+ if (allocacc!=NULL) free(allocacc); /* drop any storage used */
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ #if FASTMUL
+ if (allocrhi!=NULL) free(allocrhi); /* .. */
+ if (alloclhi!=NULL) free(alloclhi); /* .. */
+ #endif
+ return res;
+ } /* decMultiplyOp */
+
+/* ------------------------------------------------------------------ */
+/* decExpOp -- effect exponentiation */
+/* */
+/* This computes C = exp(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. status is updated but */
+/* not set. */
+/* */
+/* Restrictions: */
+/* */
+/* digits, emax, and -emin in the context must be less than */
+/* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */
+/* bounds or a zero. This is an internal routine, so these */
+/* restrictions are contractual and not enforced. */
+/* */
+/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* */
+/* Finite results will always be full precision and Inexact, except */
+/* when A is a zero or -Infinity (giving 1 or 0 respectively). */
+/* ------------------------------------------------------------------ */
+/* This approach used here is similar to the algorithm described in */
+/* */
+/* Variable Precision Exponential Function, T. E. Hull and */
+/* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */
+/* pp79-91, ACM, June 1986. */
+/* */
+/* with the main difference being that the iterations in the series */
+/* evaluation are terminated dynamically (which does not require the */
+/* extra variable-precision variables which are expensive in this */
+/* context). */
+/* */
+/* The error analysis in Hull & Abrham's paper applies except for the */
+/* round-off error accumulation during the series evaluation. This */
+/* code does not precalculate the number of iterations and so cannot */
+/* use Horner's scheme. Instead, the accumulation is done at double- */
+/* precision, which ensures that the additions of the terms are exact */
+/* and do not accumulate round-off (and any round-off errors in the */
+/* terms themselves move 'to the right' faster than they can */
+/* accumulate). This code also extends the calculation by allowing, */
+/* in the spirit of other decNumber operators, the input to be more */
+/* precise than the result (the precision used is based on the more */
+/* precise of the input or requested result). */
+/* */
+/* Implementation notes: */
+/* */
+/* 1. This is separated out as decExpOp so it can be called from */
+/* other Mathematical functions (notably Ln) with a wider range */
+/* than normal. In particular, it can handle the slightly wider */
+/* (double) range needed by Ln (which has to be able to calculate */
+/* exp(-x) where x can be the tiniest number (Ntiny). */
+/* */
+/* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */
+/* iterations by appoximately a third with additional (although */
+/* diminishing) returns as the range is reduced to even smaller */
+/* fractions. However, h (the power of 10 used to correct the */
+/* result at the end, see below) must be kept <=8 as otherwise */
+/* the final result cannot be computed. Hence the leverage is a */
+/* sliding value (8-h), where potentially the range is reduced */
+/* more for smaller values. */
+/* */
+/* The leverage that can be applied in this way is severely */
+/* limited by the cost of the raise-to-the power at the end, */
+/* which dominates when the number of iterations is small (less */
+/* than ten) or when rhs is short. As an example, the adjustment */
+/* x**10,000,000 needs 31 multiplications, all but one full-width. */
+/* */
+/* 3. The restrictions (especially precision) could be raised with */
+/* care, but the full decNumber range seems very hard within the */
+/* 32-bit limits. */
+/* */
+/* 4. The working precisions for the static buffers are twice the */
+/* obvious size to allow for calls from decNumberPower. */
+/* ------------------------------------------------------------------ */
+decNumber * decExpOp(decNumber *res, const decNumber *rhs,
+ decContext *set, uInt *status) {
+ uInt ignore=0; /* working status */
+ Int h; /* adjusted exponent for 0.xxxx */
+ Int p; /* working precision */
+ Int residue; /* rounding residue */
+ uInt needbytes; /* for space calculations */
+ const decNumber *x=rhs; /* (may point to safe copy later) */
+ decContext aset, tset, dset; /* working contexts */
+ Int comp; /* work */
+
+ /* the argument is often copied to normalize it, so (unusually) it */
+ /* is treated like other buffers, using DECBUFFER, +1 in case */
+ /* DECBUFFER is 0 */
+ decNumber bufr[D2N(DECBUFFER*2+1)];
+ decNumber *allocrhs=NULL; /* non-NULL if rhs buffer allocated */
+
+ /* the working precision will be no more than set->digits+8+1 */
+ /* so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER */
+ /* is 0 (and twice that for the accumulator) */
+
+ /* buffer for t, term (working precision plus) */
+ decNumber buft[D2N(DECBUFFER*2+9+1)];
+ decNumber *allocbuft=NULL; /* -> allocated buft, iff allocated */
+ decNumber *t=buft; /* term */
+ /* buffer for a, accumulator (working precision * 2), at least 9 */
+ decNumber bufa[D2N(DECBUFFER*4+18+1)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *a=bufa; /* accumulator */
+ /* decNumber for the divisor term; this needs at most 9 digits */
+ /* and so can be fixed size [16 so can use standard context] */
+ decNumber bufd[D2N(16)];
+ decNumber *d=bufd; /* divisor */
+ decNumber numone; /* constant 1 */
+
+ #if DECCHECK
+ Int iterations=0; /* for later sanity check */
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ if (SPECIALARG) { /* handle infinities and NaNs */
+ if (decNumberIsInfinite(rhs)) { /* an infinity */
+ if (decNumberIsNegative(rhs)) /* -Infinity -> +0 */
+ uprv_decNumberZero(res);
+ else uprv_decNumberCopy(res, rhs); /* +Infinity -> self */
+ }
+ else decNaNs(res, rhs, NULL, set, status); /* a NaN */
+ break;}
+
+ if (ISZERO(rhs)) { /* zeros -> exact 1 */
+ uprv_decNumberZero(res); /* make clean 1 */
+ *res->lsu=1; /* .. */
+ break;} /* [no status to set] */
+
+ /* e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path */
+ /* positive and negative tiny cases which will result in inexact */
+ /* 1. This also allows the later add-accumulate to always be */
+ /* exact (because its length will never be more than twice the */
+ /* working precision). */
+ /* The comparator (tiny) needs just one digit, so use the */
+ /* decNumber d for it (reused as the divisor, etc., below); its */
+ /* exponent is such that if x is positive it will have */
+ /* set->digits-1 zeros between the decimal point and the digit, */
+ /* which is 4, and if x is negative one more zero there as the */
+ /* more precise result will be of the form 0.9999999 rather than */
+ /* 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 */
+ /* or 0.00000004 if digits=7 and x<0. If RHS not larger than */
+ /* this then the result will be 1.000000 */
+ uprv_decNumberZero(d); /* clean */
+ *d->lsu=4; /* set 4 .. */
+ d->exponent=-set->digits; /* * 10**(-d) */
+ if (decNumberIsNegative(rhs)) d->exponent--; /* negative case */
+ comp=decCompare(d, rhs, 1); /* signless compare */
+ if (comp==BADINT) {
+ *status|=DEC_Insufficient_storage;
+ break;}
+ if (comp>=0) { /* rhs < d */
+ Int shift=set->digits-1;
+ uprv_decNumberZero(res); /* set 1 */
+ *res->lsu=1; /* .. */
+ res->digits=decShiftToMost(res->lsu, 1, shift);
+ res->exponent=-shift; /* make 1.0000... */
+ *status|=DEC_Inexact | DEC_Rounded; /* .. inexactly */
+ break;} /* tiny */
+
+ /* set up the context to be used for calculating a, as this is */
+ /* used on both paths below */
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64);
+ /* accumulator bounds are as requested (could underflow) */
+ aset.emax=set->emax; /* usual bounds */
+ aset.emin=set->emin; /* .. */
+ aset.clamp=0; /* and no concrete format */
+
+ /* calculate the adjusted (Hull & Abrham) exponent (where the */
+ /* decimal point is just to the left of the coefficient msd) */
+ h=rhs->exponent+rhs->digits;
+ /* if h>8 then 10**h cannot be calculated safely; however, when */
+ /* h=8 then exp(|rhs|) will be at least exp(1E+7) which is at */
+ /* least 6.59E+4342944, so (due to the restriction on Emax/Emin) */
+ /* overflow (or underflow to 0) is guaranteed -- so this case can */
+ /* be handled by simply forcing the appropriate excess */
+ if (h>8) { /* overflow/underflow */
+ /* set up here so Power call below will over or underflow to */
+ /* zero; set accumulator to either 2 or 0.02 */
+ /* [stack buffer for a is always big enough for this] */
+ uprv_decNumberZero(a);
+ *a->lsu=2; /* not 1 but < exp(1) */
+ if (decNumberIsNegative(rhs)) a->exponent=-2; /* make 0.02 */
+ h=8; /* clamp so 10**h computable */
+ p=9; /* set a working precision */
+ }
+ else { /* h<=8 */
+ Int maxlever=(rhs->digits>8?1:0);
+ /* [could/should increase this for precisions >40 or so, too] */
+
+ /* if h is 8, cannot normalize to a lower upper limit because */
+ /* the final result will not be computable (see notes above), */
+ /* but leverage can be applied whenever h is less than 8. */
+ /* Apply as much as possible, up to a MAXLEVER digits, which */
+ /* sets the tradeoff against the cost of the later a**(10**h). */
+ /* As h is increased, the working precision below also */
+ /* increases to compensate for the "constant digits at the */
+ /* front" effect. */
+ Int lever=MINI(8-h, maxlever); /* leverage attainable */
+ Int use=-rhs->digits-lever; /* exponent to use for RHS */
+ h+=lever; /* apply leverage selected */
+ if (h<0) { /* clamp */
+ use+=h; /* [may end up subnormal] */
+ h=0;
+ }
+ /* Take a copy of RHS if it needs normalization (true whenever x>=1) */
+ if (rhs->exponent!=use) {
+ decNumber *newrhs=bufr; /* assume will fit on stack */
+ needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufr)) { /* need malloc space */
+ allocrhs=(decNumber *)malloc(needbytes);
+ if (allocrhs==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ newrhs=allocrhs; /* use the allocated space */
+ }
+ uprv_decNumberCopy(newrhs, rhs); /* copy to safe space */
+ newrhs->exponent=use; /* normalize; now <1 */
+ x=newrhs; /* ready for use */
+ /* decNumberShow(x); */
+ }
+
+ /* Now use the usual power series to evaluate exp(x). The */
+ /* series starts as 1 + x + x^2/2 ... so prime ready for the */
+ /* third term by setting the term variable t=x, the accumulator */
+ /* a=1, and the divisor d=2. */
+
+ /* First determine the working precision. From Hull & Abrham */
+ /* this is set->digits+h+2. However, if x is 'over-precise' we */
+ /* need to allow for all its digits to potentially participate */
+ /* (consider an x where all the excess digits are 9s) so in */
+ /* this case use x->digits+h+2 */
+ p=MAXI(x->digits, set->digits)+h+2; /* [h<=8] */
+
+ /* a and t are variable precision, and depend on p, so space */
+ /* must be allocated for them if necessary */
+
+ /* the accumulator needs to be able to hold 2p digits so that */
+ /* the additions on the second and subsequent iterations are */
+ /* sufficiently exact. */
+ needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ /* the term needs to be able to hold p digits (which is */
+ /* guaranteed to be larger than x->digits, so the initial copy */
+ /* is safe); it may also be used for the raise-to-power */
+ /* calculation below, which needs an extra two digits */
+ needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit);
+ if (needbytes>sizeof(buft)) { /* need malloc space */
+ allocbuft=(decNumber *)malloc(needbytes);
+ if (allocbuft==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ t=allocbuft; /* use the allocated space */
+ }
+
+ uprv_decNumberCopy(t, x); /* term=x */
+ uprv_decNumberZero(a); *a->lsu=1; /* accumulator=1 */
+ uprv_decNumberZero(d); *d->lsu=2; /* divisor=2 */
+ uprv_decNumberZero(&numone); *numone.lsu=1; /* constant 1 for increment */
+
+ /* set up the contexts for calculating a, t, and d */
+ uprv_decContextDefault(&tset, DEC_INIT_DECIMAL64);
+ dset=tset;
+ /* accumulator bounds are set above, set precision now */
+ aset.digits=p*2; /* double */
+ /* term bounds avoid any underflow or overflow */
+ tset.digits=p;
+ tset.emin=DEC_MIN_EMIN; /* [emax is plenty] */
+ /* [dset.digits=16, etc., are sufficient] */
+
+ /* finally ready to roll */
+ for (;;) {
+ #if DECCHECK
+ iterations++;
+ #endif
+ /* only the status from the accumulation is interesting */
+ /* [but it should remain unchanged after first add] */
+ decAddOp(a, a, t, &aset, 0, status); /* a=a+t */
+ decMultiplyOp(t, t, x, &tset, &ignore); /* t=t*x */
+ decDivideOp(t, t, d, &tset, DIVIDE, &ignore); /* t=t/d */
+ /* the iteration ends when the term cannot affect the result, */
+ /* if rounded to p digits, which is when its value is smaller */
+ /* than the accumulator by p+1 digits. There must also be */
+ /* full precision in a. */
+ if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1))
+ && (a->digits>=p)) break;
+ decAddOp(d, d, &numone, &dset, 0, &ignore); /* d=d+1 */
+ } /* iterate */
+
+ #if DECCHECK
+ /* just a sanity check; comment out test to show always */
+ if (iterations>p+3)
+ printf("Exp iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
+ (LI)iterations, (LI)*status, (LI)p, (LI)x->digits);
+ #endif
+ } /* h<=8 */
+
+ /* apply postconditioning: a=a**(10**h) -- this is calculated */
+ /* at a slightly higher precision than Hull & Abrham suggest */
+ if (h>0) {
+ Int seenbit=0; /* set once a 1-bit is seen */
+ Int i; /* counter */
+ Int n=powers[h]; /* always positive */
+ aset.digits=p+2; /* sufficient precision */
+ /* avoid the overhead and many extra digits of decNumberPower */
+ /* as all that is needed is the short 'multipliers' loop; here */
+ /* accumulate the answer into t */
+ uprv_decNumberZero(t); *t->lsu=1; /* acc=1 */
+ for (i=1;;i++){ /* for each bit [top bit ignored] */
+ /* abandon if have had overflow or terminal underflow */
+ if (*status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
+ if (*status&DEC_Overflow || ISZERO(t)) break;}
+ n=n<<1; /* move next bit to testable position */
+ if (n<0) { /* top bit is set */
+ seenbit=1; /* OK, have a significant bit */
+ decMultiplyOp(t, t, a, &aset, status); /* acc=acc*x */
+ }
+ if (i==31) break; /* that was the last bit */
+ if (!seenbit) continue; /* no need to square 1 */
+ decMultiplyOp(t, t, t, &aset, status); /* acc=acc*acc [square] */
+ } /*i*/ /* 32 bits */
+ /* decNumberShow(t); */
+ a=t; /* and carry on using t instead of a */
+ }
+
+ /* Copy and round the result to res */
+ residue=1; /* indicate dirt to right .. */
+ if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
+ aset.digits=set->digits; /* [use default rounding] */
+ decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
+ decFinish(res, set, &residue, status); /* cleanup/set flags */
+ } while(0); /* end protected */
+
+ if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
+ if (allocbufa!=NULL) free(allocbufa); /* .. */
+ if (allocbuft!=NULL) free(allocbuft); /* .. */
+ /* [status is handled by caller] */
+ return res;
+ } /* decExpOp */
+
+/* ------------------------------------------------------------------ */
+/* Initial-estimate natural logarithm table */
+/* */
+/* LNnn -- 90-entry 16-bit table for values from .10 through .99. */
+/* The result is a 4-digit encode of the coefficient (c=the */
+/* top 14 bits encoding 0-9999) and a 2-digit encode of the */
+/* exponent (e=the bottom 2 bits encoding 0-3) */
+/* */
+/* The resulting value is given by: */
+/* */
+/* v = -c * 10**(-e-3) */
+/* */
+/* where e and c are extracted from entry k = LNnn[x-10] */
+/* where x is truncated (NB) into the range 10 through 99, */
+/* and then c = k>>2 and e = k&3. */
+/* ------------------------------------------------------------------ */
+const uShort LNnn[90]={9016, 8652, 8316, 8008, 7724, 7456, 7208,
+ 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312,
+ 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032,
+ 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629,
+ 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837,
+ 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321,
+ 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717,
+ 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801,
+ 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254,
+ 10130, 6046, 20055};
+
+/* ------------------------------------------------------------------ */
+/* decLnOp -- effect natural logarithm */
+/* */
+/* This computes C = ln(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Notable cases: */
+/* A<0 -> Invalid */
+/* A=0 -> -Infinity (Exact) */
+/* A=+Infinity -> +Infinity (Exact) */
+/* A=1 exactly -> 0 (Exact) */
+/* */
+/* Restrictions (as for Exp): */
+/* */
+/* digits, emax, and -emin in the context must be less than */
+/* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */
+/* bounds or a zero. This is an internal routine, so these */
+/* restrictions are contractual and not enforced. */
+/* */
+/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* The result is calculated using Newton's method, with each */
+/* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */
+/* Epperson 1989. */
+/* */
+/* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */
+/* This has to be calculated at the sum of the precision of x and the */
+/* working precision. */
+/* */
+/* Implementation notes: */
+/* */
+/* 1. This is separated out as decLnOp so it can be called from */
+/* other Mathematical functions (e.g., Log 10) with a wider range */
+/* than normal. In particular, it can handle the slightly wider */
+/* (+9+2) range needed by a power function. */
+/* */
+/* 2. The speed of this function is about 10x slower than exp, as */
+/* it typically needs 4-6 iterations for short numbers, and the */
+/* extra precision needed adds a squaring effect, twice. */
+/* */
+/* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */
+/* as these are common requests. ln(10) is used by log10(x). */
+/* */
+/* 4. An iteration might be saved by widening the LNnn table, and */
+/* would certainly save at least one if it were made ten times */
+/* bigger, too (for truncated fractions 0.100 through 0.999). */
+/* However, for most practical evaluations, at least four or five */
+/* iterations will be neede -- so this would only speed up by */
+/* 20-25% and that probably does not justify increasing the table */
+/* size. */
+/* */
+/* 5. The static buffers are larger than might be expected to allow */
+/* for calls from decNumberPower. */
+/* ------------------------------------------------------------------ */
+decNumber * decLnOp(decNumber *res, const decNumber *rhs,
+ decContext *set, uInt *status) {
+ uInt ignore=0; /* working status accumulator */
+ uInt needbytes; /* for space calculations */
+ Int residue; /* rounding residue */
+ Int r; /* rhs=f*10**r [see below] */
+ Int p; /* working precision */
+ Int pp; /* precision for iteration */
+ Int t; /* work */
+
+ /* buffers for a (accumulator, typically precision+2) and b */
+ /* (adjustment calculator, same size) */
+ decNumber bufa[D2N(DECBUFFER+12)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *a=bufa; /* accumulator/work */
+ decNumber bufb[D2N(DECBUFFER*2+2)];
+ decNumber *allocbufb=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *b=bufb; /* adjustment/work */
+
+ decNumber numone; /* constant 1 */
+ decNumber cmp; /* work */
+ decContext aset, bset; /* working contexts */
+
+ #if DECCHECK
+ Int iterations=0; /* for later sanity check */
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ if (SPECIALARG) { /* handle infinities and NaNs */
+ if (decNumberIsInfinite(rhs)) { /* an infinity */
+ if (decNumberIsNegative(rhs)) /* -Infinity -> error */
+ *status|=DEC_Invalid_operation;
+ else uprv_decNumberCopy(res, rhs); /* +Infinity -> self */
+ }
+ else decNaNs(res, rhs, NULL, set, status); /* a NaN */
+ break;}
+
+ if (ISZERO(rhs)) { /* +/- zeros -> -Infinity */
+ uprv_decNumberZero(res); /* make clean */
+ res->bits=DECINF|DECNEG; /* set - infinity */
+ break;} /* [no status to set] */
+
+ /* Non-zero negatives are bad... */
+ if (decNumberIsNegative(rhs)) { /* -x -> error */
+ *status|=DEC_Invalid_operation;
+ break;}
+
+ /* Here, rhs is positive, finite, and in range */
+
+ /* lookaside fastpath code for ln(2) and ln(10) at common lengths */
+ if (rhs->exponent==0 && set->digits<=40) {
+ #if DECDPUN==1
+ if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { /* ln(10) */
+ #else
+ if (rhs->lsu[0]==10 && rhs->digits==2) { /* ln(10) */
+ #endif
+ aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
+ #define LN10 "2.302585092994045684017991454684364207601"
+ uprv_decNumberFromString(res, LN10, &aset);
+ *status|=(DEC_Inexact | DEC_Rounded); /* is inexact */
+ break;}
+ if (rhs->lsu[0]==2 && rhs->digits==1) { /* ln(2) */
+ aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
+ #define LN2 "0.6931471805599453094172321214581765680755"
+ uprv_decNumberFromString(res, LN2, &aset);
+ *status|=(DEC_Inexact | DEC_Rounded);
+ break;}
+ } /* integer and short */
+
+ /* Determine the working precision. This is normally the */
+ /* requested precision + 2, with a minimum of 9. However, if */
+ /* the rhs is 'over-precise' then allow for all its digits to */
+ /* potentially participate (consider an rhs where all the excess */
+ /* digits are 9s) so in this case use rhs->digits+2. */
+ p=MAXI(rhs->digits, MAXI(set->digits, 7))+2;
+
+ /* Allocate space for the accumulator and the high-precision */
+ /* adjustment calculator, if necessary. The accumulator must */
+ /* be able to hold p digits, and the adjustment up to */
+ /* rhs->digits+p digits. They are also made big enough for 16 */
+ /* digits so that they can be used for calculating the initial */
+ /* estimate. */
+ needbytes=sizeof(decNumber)+(D2U(MAXI(p,16))-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ pp=p+rhs->digits;
+ needbytes=sizeof(decNumber)+(D2U(MAXI(pp,16))-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufb)) { /* need malloc space */
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufb==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ b=allocbufb; /* use the allocated space */
+ }
+
+ /* Prepare an initial estimate in acc. Calculate this by */
+ /* considering the coefficient of x to be a normalized fraction, */
+ /* f, with the decimal point at far left and multiplied by */
+ /* 10**r. Then, rhs=f*10**r and 0.1<=f<1, and */
+ /* ln(x) = ln(f) + ln(10)*r */
+ /* Get the initial estimate for ln(f) from a small lookup */
+ /* table (see above) indexed by the first two digits of f, */
+ /* truncated. */
+
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* 16-digit extended */
+ r=rhs->exponent+rhs->digits; /* 'normalised' exponent */
+ uprv_decNumberFromInt32(a, r); /* a=r */
+ uprv_decNumberFromInt32(b, 2302585); /* b=ln(10) (2.302585) */
+ b->exponent=-6; /* .. */
+ decMultiplyOp(a, a, b, &aset, &ignore); /* a=a*b */
+ /* now get top two digits of rhs into b by simple truncate and */
+ /* force to integer */
+ residue=0; /* (no residue) */
+ aset.digits=2; aset.round=DEC_ROUND_DOWN;
+ decCopyFit(b, rhs, &aset, &residue, &ignore); /* copy & shorten */
+ b->exponent=0; /* make integer */
+ t=decGetInt(b); /* [cannot fail] */
+ if (t<10) t=X10(t); /* adjust single-digit b */
+ t=LNnn[t-10]; /* look up ln(b) */
+ uprv_decNumberFromInt32(b, t>>2); /* b=ln(b) coefficient */
+ b->exponent=-(t&3)-3; /* set exponent */
+ b->bits=DECNEG; /* ln(0.10)->ln(0.99) always -ve */
+ aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; /* restore */
+ decAddOp(a, a, b, &aset, 0, &ignore); /* acc=a+b */
+ /* the initial estimate is now in a, with up to 4 digits correct. */
+ /* When rhs is at or near Nmax the estimate will be low, so we */
+ /* will approach it from below, avoiding overflow when calling exp. */
+
+ uprv_decNumberZero(&numone); *numone.lsu=1; /* constant 1 for adjustment */
+
+ /* accumulator bounds are as requested (could underflow, but */
+ /* cannot overflow) */
+ aset.emax=set->emax;
+ aset.emin=set->emin;
+ aset.clamp=0; /* no concrete format */
+ /* set up a context to be used for the multiply and subtract */
+ bset=aset;
+ bset.emax=DEC_MAX_MATH*2; /* use double bounds for the */
+ bset.emin=-DEC_MAX_MATH*2; /* adjustment calculation */
+ /* [see decExpOp call below] */
+ /* for each iteration double the number of digits to calculate, */
+ /* up to a maximum of p */
+ pp=9; /* initial precision */
+ /* [initially 9 as then the sequence starts 7+2, 16+2, and */
+ /* 34+2, which is ideal for standard-sized numbers] */
+ aset.digits=pp; /* working context */
+ bset.digits=pp+rhs->digits; /* wider context */
+ for (;;) { /* iterate */
+ #if DECCHECK
+ iterations++;
+ if (iterations>24) break; /* consider 9 * 2**24 */
+ #endif
+ /* calculate the adjustment (exp(-a)*x-1) into b. This is a */
+ /* catastrophic subtraction but it really is the difference */
+ /* from 1 that is of interest. */
+ /* Use the internal entry point to Exp as it allows the double */
+ /* range for calculating exp(-a) when a is the tiniest subnormal. */
+ a->bits^=DECNEG; /* make -a */
+ decExpOp(b, a, &bset, &ignore); /* b=exp(-a) */
+ a->bits^=DECNEG; /* restore sign of a */
+ /* now multiply by rhs and subtract 1, at the wider precision */
+ decMultiplyOp(b, b, rhs, &bset, &ignore); /* b=b*rhs */
+ decAddOp(b, b, &numone, &bset, DECNEG, &ignore); /* b=b-1 */
+
+ /* the iteration ends when the adjustment cannot affect the */
+ /* result by >=0.5 ulp (at the requested digits), which */
+ /* is when its value is smaller than the accumulator by */
+ /* set->digits+1 digits (or it is zero) -- this is a looser */
+ /* requirement than for Exp because all that happens to the */
+ /* accumulator after this is the final rounding (but note that */
+ /* there must also be full precision in a, or a=0). */
+
+ if (decNumberIsZero(b) ||
+ (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) {
+ if (a->digits==p) break;
+ if (decNumberIsZero(a)) {
+ decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); /* rhs=1 ? */
+ if (cmp.lsu[0]==0) a->exponent=0; /* yes, exact 0 */
+ else *status|=(DEC_Inexact | DEC_Rounded); /* no, inexact */
+ break;
+ }
+ /* force padding if adjustment has gone to 0 before full length */
+ if (decNumberIsZero(b)) b->exponent=a->exponent-p;
+ }
+
+ /* not done yet ... */
+ decAddOp(a, a, b, &aset, 0, &ignore); /* a=a+b for next estimate */
+ if (pp==p) continue; /* precision is at maximum */
+ /* lengthen the next calculation */
+ pp=pp*2; /* double precision */
+ if (pp>p) pp=p; /* clamp to maximum */
+ aset.digits=pp; /* working context */
+ bset.digits=pp+rhs->digits; /* wider context */
+ } /* Newton's iteration */
+
+ #if DECCHECK
+ /* just a sanity check; remove the test to show always */
+ if (iterations>24)
+ printf("Ln iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
+ (LI)iterations, (LI)*status, (LI)p, (LI)rhs->digits);
+ #endif
+
+ /* Copy and round the result to res */
+ residue=1; /* indicate dirt to right */
+ if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
+ aset.digits=set->digits; /* [use default rounding] */
+ decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
+ decFinish(res, set, &residue, status); /* cleanup/set flags */
+ } while(0); /* end protected */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ /* [status is handled by caller] */
+ return res;
+ } /* decLnOp */
+
+/* ------------------------------------------------------------------ */
+/* decQuantizeOp -- force exponent to requested value */
+/* */
+/* This computes C = op(A, B), where op adjusts the coefficient */
+/* of C (by rounding or shifting) such that the exponent (-scale) */
+/* of C has the value B or matches the exponent of B. */
+/* The numerical value of C will equal A, except for the effects of */
+/* any rounding that occurred. */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the requested exponent */
+/* set is the context */
+/* quant is 1 for quantize or 0 for rescale */
+/* status is the status accumulator (this can be called without */
+/* risk of control loss) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Unless there is an error or the result is infinite, the exponent */
+/* after the operation is guaranteed to be that requested. */
+/* ------------------------------------------------------------------ */
+static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ Flag quant, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ const decNumber *inrhs=rhs; /* save original rhs */
+ Int reqdigits=set->digits; /* requested DIGITS */
+ Int reqexp; /* requested exponent [-scale] */
+ Int residue=0; /* rounding residue */
+ Int etiny=set->emin-(reqdigits-1);
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) { /* [this only checks lostDigits] */
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* Handle special values */
+ if (SPECIALARGS) {
+ /* NaNs get usual processing */
+ if (SPECIALARGS & (DECSNAN | DECNAN))
+ decNaNs(res, lhs, rhs, set, status);
+ /* one infinity but not both is bad */
+ else if ((lhs->bits ^ rhs->bits) & DECINF)
+ *status|=DEC_Invalid_operation;
+ /* both infinity: return lhs */
+ else uprv_decNumberCopy(res, lhs); /* [nop if in place] */
+ break;
+ }
+
+ /* set requested exponent */
+ if (quant) reqexp=inrhs->exponent; /* quantize -- match exponents */
+ else { /* rescale -- use value of rhs */
+ /* Original rhs must be an integer that fits and is in range, */
+ /* which could be from -1999999997 to +999999999, thanks to */
+ /* subnormals */
+ reqexp=decGetInt(inrhs); /* [cannot fail] */
+ }
+
+ #if DECSUBSET
+ if (!set->extended) etiny=set->emin; /* no subnormals */
+ #endif
+
+ if (reqexp==BADINT /* bad (rescale only) or .. */
+ || reqexp==BIGODD || reqexp==BIGEVEN /* very big (ditto) or .. */
+ || (reqexp<etiny) /* < lowest */
+ || (reqexp>set->emax)) { /* > emax */
+ *status|=DEC_Invalid_operation;
+ break;}
+
+ /* the RHS has been processed, so it can be overwritten now if necessary */
+ if (ISZERO(lhs)) { /* zero coefficient unchanged */
+ uprv_decNumberCopy(res, lhs); /* [nop if in place] */
+ res->exponent=reqexp; /* .. just set exponent */
+ #if DECSUBSET
+ if (!set->extended) res->bits=0; /* subset specification; no -0 */
+ #endif
+ }
+ else { /* non-zero lhs */
+ Int adjust=reqexp-lhs->exponent; /* digit adjustment needed */
+ /* if adjusted coefficient will definitely not fit, give up now */
+ if ((lhs->digits-adjust)>reqdigits) {
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+
+ if (adjust>0) { /* increasing exponent */
+ /* this will decrease the length of the coefficient by adjust */
+ /* digits, and must round as it does so */
+ decContext workset; /* work */
+ workset=*set; /* clone rounding, etc. */
+ workset.digits=lhs->digits-adjust; /* set requested length */
+ /* [note that the latter can be <1, here] */
+ decCopyFit(res, lhs, &workset, &residue, status); /* fit to result */
+ decApplyRound(res, &workset, residue, status); /* .. and round */
+ residue=0; /* [used] */
+ /* If just rounded a 999s case, exponent will be off by one; */
+ /* adjust back (after checking space), if so. */
+ if (res->exponent>reqexp) {
+ /* re-check needed, e.g., for quantize(0.9999, 0.001) under */
+ /* set->digits==3 */
+ if (res->digits==reqdigits) { /* cannot shift by 1 */
+ *status&=~(DEC_Inexact | DEC_Rounded); /* [clean these] */
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ res->digits=decShiftToMost(res->lsu, res->digits, 1); /* shift */
+ res->exponent--; /* (re)adjust the exponent. */
+ }
+ #if DECSUBSET
+ if (ISZERO(res) && !set->extended) res->bits=0; /* subset; no -0 */
+ #endif
+ } /* increase */
+ else /* adjust<=0 */ { /* decreasing or = exponent */
+ /* this will increase the length of the coefficient by -adjust */
+ /* digits, by adding zero or more trailing zeros; this is */
+ /* already checked for fit, above */
+ uprv_decNumberCopy(res, lhs); /* [it will fit] */
+ /* if padding needed (adjust<0), add it now... */
+ if (adjust<0) {
+ res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
+ res->exponent+=adjust; /* adjust the exponent */
+ }
+ } /* decrease */
+ } /* non-zero */
+
+ /* Check for overflow [do not use Finalize in this case, as an */
+ /* overflow here is a "don't fit" situation] */
+ if (res->exponent>set->emax-res->digits+1) { /* too big */
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ else {
+ decFinalize(res, set, &residue, status); /* set subnormal flags */
+ *status&=~DEC_Underflow; /* suppress Underflow [as per 754] */
+ }
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* drop any storage used */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decQuantizeOp */
+
+/* ------------------------------------------------------------------ */
+/* decCompareOp -- compare, min, or max two Numbers */
+/* */
+/* This computes C = A ? B and carries out one of four operations: */
+/* COMPARE -- returns the signum (as a number) giving the */
+/* result of a comparison unless one or both */
+/* operands is a NaN (in which case a NaN results) */
+/* COMPSIG -- as COMPARE except that a quiet NaN raises */
+/* Invalid operation. */
+/* COMPMAX -- returns the larger of the operands, using the */
+/* 754 maxnum operation */
+/* COMPMAXMAG -- ditto, comparing absolute values */
+/* COMPMIN -- the 754 minnum operation */
+/* COMPMINMAG -- ditto, comparing absolute values */
+/* COMTOTAL -- returns the signum (as a number) giving the */
+/* result of a comparison using 754 total ordering */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* op is the operation flag */
+/* status is the usual accumulator */
+/* */
+/* C must have space for one digit for COMPARE or set->digits for */
+/* COMPMAX, COMPMIN, COMPMAXMAG, or COMPMINMAG. */
+/* ------------------------------------------------------------------ */
+/* The emphasis here is on speed for common cases, and avoiding */
+/* coefficient comparison if possible. */
+/* ------------------------------------------------------------------ */
+static decNumber * decCompareOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ Flag op, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ Int result=0; /* default result value */
+ uByte merged; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>set->digits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) {result=BADINT; break;}
+ lhs=alloclhs;
+ }
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) {result=BADINT; break;}
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* If total ordering then handle differing signs 'up front' */
+ if (op==COMPTOTAL) { /* total ordering */
+ if (decNumberIsNegative(lhs) & !decNumberIsNegative(rhs)) {
+ result=-1;
+ break;
+ }
+ if (!decNumberIsNegative(lhs) & decNumberIsNegative(rhs)) {
+ result=+1;
+ break;
+ }
+ }
+
+ /* handle NaNs specially; let infinities drop through */
+ /* This assumes sNaN (even just one) leads to NaN. */
+ merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN);
+ if (merged) { /* a NaN bit set */
+ if (op==COMPARE); /* result will be NaN */
+ else if (op==COMPSIG) /* treat qNaN as sNaN */
+ *status|=DEC_Invalid_operation | DEC_sNaN;
+ else if (op==COMPTOTAL) { /* total ordering, always finite */
+ /* signs are known to be the same; compute the ordering here */
+ /* as if the signs are both positive, then invert for negatives */
+ if (!decNumberIsNaN(lhs)) result=-1;
+ else if (!decNumberIsNaN(rhs)) result=+1;
+ /* here if both NaNs */
+ else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1;
+ else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1;
+ else { /* both NaN or both sNaN */
+ /* now it just depends on the payload */
+ result=decUnitCompare(lhs->lsu, D2U(lhs->digits),
+ rhs->lsu, D2U(rhs->digits), 0);
+ /* [Error not possible, as these are 'aligned'] */
+ } /* both same NaNs */
+ if (decNumberIsNegative(lhs)) result=-result;
+ break;
+ } /* total order */
+
+ else if (merged & DECSNAN); /* sNaN -> qNaN */
+ else { /* here if MIN or MAX and one or two quiet NaNs */
+ /* min or max -- 754 rules ignore single NaN */
+ if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) {
+ /* just one NaN; force choice to be the non-NaN operand */
+ op=COMPMAX;
+ if (lhs->bits & DECNAN) result=-1; /* pick rhs */
+ else result=+1; /* pick lhs */
+ break;
+ }
+ } /* max or min */
+ op=COMPNAN; /* use special path */
+ decNaNs(res, lhs, rhs, set, status); /* propagate NaN */
+ break;
+ }
+ /* have numbers */
+ if (op==COMPMAXMAG || op==COMPMINMAG) result=decCompare(lhs, rhs, 1);
+ else result=decCompare(lhs, rhs, 0); /* sign matters */
+ } while(0); /* end protected */
+
+ if (result==BADINT) *status|=DEC_Insufficient_storage; /* rare */
+ else {
+ if (op==COMPARE || op==COMPSIG ||op==COMPTOTAL) { /* returning signum */
+ if (op==COMPTOTAL && result==0) {
+ /* operands are numerically equal or same NaN (and same sign, */
+ /* tested first); if identical, leave result 0 */
+ if (lhs->exponent!=rhs->exponent) {
+ if (lhs->exponent<rhs->exponent) result=-1;
+ else result=+1;
+ if (decNumberIsNegative(lhs)) result=-result;
+ } /* lexp!=rexp */
+ } /* total-order by exponent */
+ uprv_decNumberZero(res); /* [always a valid result] */
+ if (result!=0) { /* must be -1 or +1 */
+ *res->lsu=1;
+ if (result<0) res->bits=DECNEG;
+ }
+ }
+ else if (op==COMPNAN); /* special, drop through */
+ else { /* MAX or MIN, non-NaN result */
+ Int residue=0; /* rounding accumulator */
+ /* choose the operand for the result */
+ const decNumber *choice;
+ if (result==0) { /* operands are numerically equal */
+ /* choose according to sign then exponent (see 754) */
+ uByte slhs=(lhs->bits & DECNEG);
+ uByte srhs=(rhs->bits & DECNEG);
+ #if DECSUBSET
+ if (!set->extended) { /* subset: force left-hand */
+ op=COMPMAX;
+ result=+1;
+ }
+ else
+ #endif
+ if (slhs!=srhs) { /* signs differ */
+ if (slhs) result=-1; /* rhs is max */
+ else result=+1; /* lhs is max */
+ }
+ else if (slhs && srhs) { /* both negative */
+ if (lhs->exponent<rhs->exponent) result=+1;
+ else result=-1;
+ /* [if equal, use lhs, technically identical] */
+ }
+ else { /* both positive */
+ if (lhs->exponent>rhs->exponent) result=+1;
+ else result=-1;
+ /* [ditto] */
+ }
+ } /* numerically equal */
+ /* here result will be non-0; reverse if looking for MIN */
+ if (op==COMPMIN || op==COMPMINMAG) result=-result;
+ choice=(result>0 ? lhs : rhs); /* choose */
+ /* copy chosen to result, rounding if need be */
+ decCopyFit(res, choice, set, &residue, status);
+ decFinish(res, set, &residue, status);
+ }
+ }
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* free any storage used */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decCompareOp */
+
+/* ------------------------------------------------------------------ */
+/* decCompare -- compare two decNumbers by numerical value */
+/* */
+/* This routine compares A ? B without altering them. */
+/* */
+/* Arg1 is A, a decNumber which is not a NaN */
+/* Arg2 is B, a decNumber which is not a NaN */
+/* Arg3 is 1 for a sign-independent compare, 0 otherwise */
+/* */
+/* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
+/* (the only possible failure is an allocation error) */
+/* ------------------------------------------------------------------ */
+static Int decCompare(const decNumber *lhs, const decNumber *rhs,
+ Flag abs_c) {
+ Int result; /* result value */
+ Int sigr; /* rhs signum */
+ Int compare; /* work */
+
+ result=1; /* assume signum(lhs) */
+ if (ISZERO(lhs)) result=0;
+ if (abs_c) {
+ if (ISZERO(rhs)) return result; /* LHS wins or both 0 */
+ /* RHS is non-zero */
+ if (result==0) return -1; /* LHS is 0; RHS wins */
+ /* [here, both non-zero, result=1] */
+ }
+ else { /* signs matter */
+ if (result && decNumberIsNegative(lhs)) result=-1;
+ sigr=1; /* compute signum(rhs) */
+ if (ISZERO(rhs)) sigr=0;
+ else if (decNumberIsNegative(rhs)) sigr=-1;
+ if (result > sigr) return +1; /* L > R, return 1 */
+ if (result < sigr) return -1; /* L < R, return -1 */
+ if (result==0) return 0; /* both 0 */
+ }
+
+ /* signums are the same; both are non-zero */
+ if ((lhs->bits | rhs->bits) & DECINF) { /* one or more infinities */
+ if (decNumberIsInfinite(rhs)) {
+ if (decNumberIsInfinite(lhs)) result=0;/* both infinite */
+ else result=-result; /* only rhs infinite */
+ }
+ return result;
+ }
+ /* must compare the coefficients, allowing for exponents */
+ if (lhs->exponent>rhs->exponent) { /* LHS exponent larger */
+ /* swap sides, and sign */
+ const decNumber *temp=lhs;
+ lhs=rhs;
+ rhs=temp;
+ result=-result;
+ }
+ compare=decUnitCompare(lhs->lsu, D2U(lhs->digits),
+ rhs->lsu, D2U(rhs->digits),
+ rhs->exponent-lhs->exponent);
+ if (compare!=BADINT) compare*=result; /* comparison succeeded */
+ return compare;
+ } /* decCompare */
+
+/* ------------------------------------------------------------------ */
+/* decUnitCompare -- compare two >=0 integers in Unit arrays */
+/* */
+/* This routine compares A ? B*10**E where A and B are unit arrays */
+/* A is a plain integer */
+/* B has an exponent of E (which must be non-negative) */
+/* */
+/* Arg1 is A first Unit (lsu) */
+/* Arg2 is A length in Units */
+/* Arg3 is B first Unit (lsu) */
+/* Arg4 is B length in Units */
+/* Arg5 is E (0 if the units are aligned) */
+/* */
+/* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
+/* (the only possible failure is an allocation error, which can */
+/* only occur if E!=0) */
+/* ------------------------------------------------------------------ */
+static Int decUnitCompare(const Unit *a, Int alength,
+ const Unit *b, Int blength, Int exp) {
+ Unit *acc; /* accumulator for result */
+ Unit accbuff[SD2U(DECBUFFER*2+1)]; /* local buffer */
+ Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
+ Int accunits, need; /* units in use or needed for acc */
+ const Unit *l, *r, *u; /* work */
+ Int expunits, exprem, result; /* .. */
+
+ if (exp==0) { /* aligned; fastpath */
+ if (alength>blength) return 1;
+ if (alength<blength) return -1;
+ /* same number of units in both -- need unit-by-unit compare */
+ l=a+alength-1;
+ r=b+alength-1;
+ for (;l>=a; l--, r--) {
+ if (*l>*r) return 1;
+ if (*l<*r) return -1;
+ }
+ return 0; /* all units match */
+ } /* aligned */
+
+ /* Unaligned. If one is >1 unit longer than the other, padded */
+ /* approximately, then can return easily */
+ if (alength>blength+(Int)D2U(exp)) return 1;
+ if (alength+1<blength+(Int)D2U(exp)) return -1;
+
+ /* Need to do a real subtract. For this, a result buffer is needed */
+ /* even though only the sign is of interest. Its length needs */
+ /* to be the larger of alength and padded blength, +2 */
+ need=blength+D2U(exp); /* maximum real length of B */
+ if (need<alength) need=alength;
+ need+=2;
+ acc=accbuff; /* assume use local buffer */
+ if (need*sizeof(Unit)>sizeof(accbuff)) {
+ allocacc=(Unit *)malloc(need*sizeof(Unit));
+ if (allocacc==NULL) return BADINT; /* hopeless -- abandon */
+ acc=allocacc;
+ }
+ /* Calculate units and remainder from exponent. */
+ expunits=exp/DECDPUN;
+ exprem=exp%DECDPUN;
+ /* subtract [A+B*(-m)] */
+ accunits=decUnitAddSub(a, alength, b, blength, expunits, acc,
+ -(Int)powers[exprem]);
+ /* [UnitAddSub result may have leading zeros, even on zero] */
+ if (accunits<0) result=-1; /* negative result */
+ else { /* non-negative result */
+ /* check units of the result before freeing any storage */
+ for (u=acc; u<acc+accunits-1 && *u==0;) u++;
+ result=(*u==0 ? 0 : +1);
+ }
+ /* clean up and return the result */
+ if (allocacc!=NULL) free(allocacc); /* drop any storage used */
+ return result;
+ } /* decUnitCompare */
+
+/* ------------------------------------------------------------------ */
+/* decUnitAddSub -- add or subtract two >=0 integers in Unit arrays */
+/* */
+/* This routine performs the calculation: */
+/* */
+/* C=A+(B*M) */
+/* */
+/* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */
+/* */
+/* A may be shorter or longer than B. */
+/* */
+/* Leading zeros are not removed after a calculation. The result is */
+/* either the same length as the longer of A and B (adding any */
+/* shift), or one Unit longer than that (if a Unit carry occurred). */
+/* */
+/* A and B content are not altered unless C is also A or B. */
+/* C may be the same array as A or B, but only if no zero padding is */
+/* requested (that is, C may be B only if bshift==0). */
+/* C is filled from the lsu; only those units necessary to complete */
+/* the calculation are referenced. */
+/* */
+/* Arg1 is A first Unit (lsu) */
+/* Arg2 is A length in Units */
+/* Arg3 is B first Unit (lsu) */
+/* Arg4 is B length in Units */
+/* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */
+/* Arg6 is C first Unit (lsu) */
+/* Arg7 is M, the multiplier */
+/* */
+/* returns the count of Units written to C, which will be non-zero */
+/* and negated if the result is negative. That is, the sign of the */
+/* returned Int is the sign of the result (positive for zero) and */
+/* the absolute value of the Int is the count of Units. */
+/* */
+/* It is the caller's responsibility to make sure that C size is */
+/* safe, allowing space if necessary for a one-Unit carry. */
+/* */
+/* This routine is severely performance-critical; *any* change here */
+/* must be measured (timed) to assure no performance degradation. */
+/* In particular, trickery here tends to be counter-productive, as */
+/* increased complexity of code hurts register optimizations on */
+/* register-poor architectures. Avoiding divisions is nearly */
+/* always a Good Idea, however. */
+/* */
+/* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */
+/* (IBM Warwick, UK) for some of the ideas used in this routine. */
+/* ------------------------------------------------------------------ */
+static Int decUnitAddSub(const Unit *a, Int alength,
+ const Unit *b, Int blength, Int bshift,
+ Unit *c, Int m) {
+ const Unit *alsu=a; /* A lsu [need to remember it] */
+ Unit *clsu=c; /* C ditto */
+ Unit *minC; /* low water mark for C */
+ Unit *maxC; /* high water mark for C */
+ eInt carry=0; /* carry integer (could be Long) */
+ Int add; /* work */
+ #if DECDPUN<=4 /* myriadal, millenary, etc. */
+ Int est; /* estimated quotient */
+ #endif
+
+ #if DECTRACE
+ if (alength<1 || blength<1)
+ printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m);
+ #endif
+
+ maxC=c+alength; /* A is usually the longer */
+ minC=c+blength; /* .. and B the shorter */
+ if (bshift!=0) { /* B is shifted; low As copy across */
+ minC+=bshift;
+ /* if in place [common], skip copy unless there's a gap [rare] */
+ if (a==c && bshift<=alength) {
+ c+=bshift;
+ a+=bshift;
+ }
+ else for (; c<clsu+bshift; a++, c++) { /* copy needed */
+ if (a<alsu+alength) *c=*a;
+ else *c=0;
+ }
+ }
+ if (minC>maxC) { /* swap */
+ Unit *hold=minC;
+ minC=maxC;
+ maxC=hold;
+ }
+
+ /* For speed, do the addition as two loops; the first where both A */
+ /* and B contribute, and the second (if necessary) where only one or */
+ /* other of the numbers contribute. */
+ /* Carry handling is the same (i.e., duplicated) in each case. */
+ for (; c<minC; c++) {
+ carry+=*a;
+ a++;
+ carry+=((eInt)*b)*m; /* [special-casing m=1/-1 */
+ b++; /* here is not a win] */
+ /* here carry is new Unit of digits; it could be +ve or -ve */
+ if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
+ *c=(Unit)carry;
+ carry=0;
+ continue;
+ }
+ #if DECDPUN==4 /* use divide-by-multiply */
+ if (carry>=0) {
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [89%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN==3
+ if (carry>=0) {
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [99%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN<=2
+ /* Can use QUOT10 as carry <= 4 digits */
+ if (carry>=0) {
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* quotient */
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ #else
+ /* remainder operator is undefined if negative, so must test */
+ if ((ueInt)carry<(DECDPUNMAX+1)*2) { /* fastpath carry +1 */
+ *c=(Unit)(carry-(DECDPUNMAX+1)); /* [helps additions] */
+ carry=1;
+ continue;
+ }
+ if (carry>=0) {
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1);
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
+ #endif
+ } /* c */
+
+ /* now may have one or other to complete */
+ /* [pretest to avoid loop setup/shutdown] */
+ if (c<maxC) for (; c<maxC; c++) {
+ if (a<alsu+alength) { /* still in A */
+ carry+=*a;
+ a++;
+ }
+ else { /* inside B */
+ carry+=((eInt)*b)*m;
+ b++;
+ }
+ /* here carry is new Unit of digits; it could be +ve or -ve and */
+ /* magnitude up to DECDPUNMAX squared */
+ if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
+ *c=(Unit)carry;
+ carry=0;
+ continue;
+ }
+ /* result for this unit is negative or >DECDPUNMAX */
+ #if DECDPUN==4 /* use divide-by-multiply */
+ if (carry>=0) {
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [79.7%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN==3
+ if (carry>=0) {
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [99%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN<=2
+ if (carry>=0) {
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* quotient */
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ #else
+ if ((ueInt)carry<(DECDPUNMAX+1)*2){ /* fastpath carry 1 */
+ *c=(Unit)(carry-(DECDPUNMAX+1));
+ carry=1;
+ continue;
+ }
+ /* remainder operator is undefined if negative, so must test */
+ if (carry>=0) {
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1);
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
+ #endif
+ } /* c */
+
+ /* OK, all A and B processed; might still have carry or borrow */
+ /* return number of Units in the result, negated if a borrow */
+ if (carry==0) return c-clsu; /* no carry, so no more to do */
+ if (carry>0) { /* positive carry */
+ *c=(Unit)carry; /* place as new unit */
+ c++; /* .. */
+ return c-clsu;
+ }
+ /* -ve carry: it's a borrow; complement needed */
+ add=1; /* temporary carry... */
+ for (c=clsu; c<maxC; c++) {
+ add=DECDPUNMAX+add-*c;
+ if (add<=DECDPUNMAX) {
+ *c=(Unit)add;
+ add=0;
+ }
+ else {
+ *c=0;
+ add=1;
+ }
+ }
+ /* add an extra unit iff it would be non-zero */
+ #if DECTRACE
+ printf("UAS borrow: add %ld, carry %ld\n", add, carry);
+ #endif
+ if ((add-carry-1)!=0) {
+ *c=(Unit)(add-carry-1);
+ c++; /* interesting, include it */
+ }
+ return clsu-c; /* -ve result indicates borrowed */
+ } /* decUnitAddSub */
+
+/* ------------------------------------------------------------------ */
+/* decTrim -- trim trailing zeros or normalize */
+/* */
+/* dn is the number to trim or normalize */
+/* set is the context to use to check for clamp */
+/* all is 1 to remove all trailing zeros, 0 for just fraction ones */
+/* noclamp is 1 to unconditional (unclamped) trim */
+/* dropped returns the number of discarded trailing zeros */
+/* returns dn */
+/* */
+/* If clamp is set in the context then the number of zeros trimmed */
+/* may be limited if the exponent is high. */
+/* All fields are updated as required. This is a utility operation, */
+/* so special values are unchanged and no error is possible. */
+/* ------------------------------------------------------------------ */
+static decNumber * decTrim(decNumber *dn, decContext *set, Flag all,
+ Flag noclamp, Int *dropped) {
+ Int d, exp; /* work */
+ uInt cut; /* .. */
+ Unit *up; /* -> current Unit */
+
+ #if DECCHECK
+ if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
+ #endif
+
+ *dropped=0; /* assume no zeros dropped */
+ if ((dn->bits & DECSPECIAL) /* fast exit if special .. */
+ || (*dn->lsu & 0x01)) return dn; /* .. or odd */
+ if (ISZERO(dn)) { /* .. or 0 */
+ dn->exponent=0; /* (sign is preserved) */
+ return dn;
+ }
+
+ /* have a finite number which is even */
+ exp=dn->exponent;
+ cut=1; /* digit (1-DECDPUN) in Unit */
+ up=dn->lsu; /* -> current Unit */
+ for (d=0; d<dn->digits-1; d++) { /* [don't strip the final digit] */
+ /* slice by powers */
+ #if DECDPUN<=4
+ uInt quot=QUOT10(*up, cut);
+ if ((*up-quot*powers[cut])!=0) break; /* found non-0 digit */
+ #else
+ if (*up%powers[cut]!=0) break; /* found non-0 digit */
+ #endif
+ /* have a trailing 0 */
+ if (!all) { /* trimming */
+ /* [if exp>0 then all trailing 0s are significant for trim] */
+ if (exp<=0) { /* if digit might be significant */
+ if (exp==0) break; /* then quit */
+ exp++; /* next digit might be significant */
+ }
+ }
+ cut++; /* next power */
+ if (cut>DECDPUN) { /* need new Unit */
+ up++;
+ cut=1;
+ }
+ } /* d */
+ if (d==0) return dn; /* none to drop */
+
+ /* may need to limit drop if clamping */
+ if (set->clamp && !noclamp) {
+ Int maxd=set->emax-set->digits+1-dn->exponent;
+ if (maxd<=0) return dn; /* nothing possible */
+ if (d>maxd) d=maxd;
+ }
+
+ /* effect the drop */
+ decShiftToLeast(dn->lsu, D2U(dn->digits), d);
+ dn->exponent+=d; /* maintain numerical value */
+ dn->digits-=d; /* new length */
+ *dropped=d; /* report the count */
+ return dn;
+ } /* decTrim */
+
+/* ------------------------------------------------------------------ */
+/* decReverse -- reverse a Unit array in place */
+/* */
+/* ulo is the start of the array */
+/* uhi is the end of the array (highest Unit to include) */
+/* */
+/* The units ulo through uhi are reversed in place (if the number */
+/* of units is odd, the middle one is untouched). Note that the */
+/* digit(s) in each unit are unaffected. */
+/* ------------------------------------------------------------------ */
+static void decReverse(Unit *ulo, Unit *uhi) {
+ Unit temp;
+ for (; ulo<uhi; ulo++, uhi--) {
+ temp=*ulo;
+ *ulo=*uhi;
+ *uhi=temp;
+ }
+ return;
+ } /* decReverse */
+
+/* ------------------------------------------------------------------ */
+/* decShiftToMost -- shift digits in array towards most significant */
+/* */
+/* uar is the array */
+/* digits is the count of digits in use in the array */
+/* shift is the number of zeros to pad with (least significant); */
+/* it must be zero or positive */
+/* */
+/* returns the new length of the integer in the array, in digits */
+/* */
+/* No overflow is permitted (that is, the uar array must be known to */
+/* be large enough to hold the result, after shifting). */
+/* ------------------------------------------------------------------ */
+static Int decShiftToMost(Unit *uar, Int digits, Int shift) {
+ Unit *target, *source, *first; /* work */
+ Int cut; /* odd 0's to add */
+ uInt next; /* work */
+
+ if (shift==0) return digits; /* [fastpath] nothing to do */
+ if ((digits+shift)<=DECDPUN) { /* [fastpath] single-unit case */
+ *uar=(Unit)(*uar*powers[shift]);
+ return digits+shift;
+ }
+
+ next=0; /* all paths */
+ source=uar+D2U(digits)-1; /* where msu comes from */
+ target=source+D2U(shift); /* where upper part of first cut goes */
+ cut=DECDPUN-MSUDIGITS(shift); /* where to slice */
+ if (cut==0) { /* unit-boundary case */
+ for (; source>=uar; source--, target--) *target=*source;
+ }
+ else {
+ first=uar+D2U(digits+shift)-1; /* where msu of source will end up */
+ for (; source>=uar; source--, target--) {
+ /* split the source Unit and accumulate remainder for next */
+ #if DECDPUN<=4
+ uInt quot=QUOT10(*source, cut);
+ uInt rem=*source-quot*powers[cut];
+ next+=quot;
+ #else
+ uInt rem=*source%powers[cut];
+ next+=*source/powers[cut];
+ #endif
+ if (target<=first) *target=(Unit)next; /* write to target iff valid */
+ next=rem*powers[DECDPUN-cut]; /* save remainder for next Unit */
+ }
+ } /* shift-move */
+
+ /* propagate any partial unit to one below and clear the rest */
+ for (; target>=uar; target--) {
+ *target=(Unit)next;
+ next=0;
+ }
+ return digits+shift;
+ } /* decShiftToMost */
+
+/* ------------------------------------------------------------------ */
+/* decShiftToLeast -- shift digits in array towards least significant */
+/* */
+/* uar is the array */
+/* units is length of the array, in units */
+/* shift is the number of digits to remove from the lsu end; it */
+/* must be zero or positive and <= than units*DECDPUN. */
+/* */
+/* returns the new length of the integer in the array, in units */
+/* */
+/* Removed digits are discarded (lost). Units not required to hold */
+/* the final result are unchanged. */
+/* ------------------------------------------------------------------ */
+static Int decShiftToLeast(Unit *uar, Int units, Int shift) {
+ Unit *target, *up; /* work */
+ Int cut, count; /* work */
+ Int quot, rem; /* for division */
+
+ if (shift==0) return units; /* [fastpath] nothing to do */
+ if (shift==units*DECDPUN) { /* [fastpath] little to do */
+ *uar=0; /* all digits cleared gives zero */
+ return 1; /* leaves just the one */
+ }
+
+ target=uar; /* both paths */
+ cut=MSUDIGITS(shift);
+ if (cut==DECDPUN) { /* unit-boundary case; easy */
+ up=uar+D2U(shift);
+ for (; up<uar+units; target++, up++) *target=*up;
+ return target-uar;
+ }
+
+ /* messier */
+ up=uar+D2U(shift-cut); /* source; correct to whole Units */
+ count=units*DECDPUN-shift; /* the maximum new length */
+ #if DECDPUN<=4
+ quot=QUOT10(*up, cut);
+ #else
+ quot=*up/powers[cut];
+ #endif
+ for (; ; target++) {
+ *target=(Unit)quot;
+ count-=(DECDPUN-cut);
+ if (count<=0) break;
+ up++;
+ quot=*up;
+ #if DECDPUN<=4
+ quot=QUOT10(quot, cut);
+ rem=*up-quot*powers[cut];
+ #else
+ rem=quot%powers[cut];
+ quot=quot/powers[cut];
+ #endif
+ *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
+ count-=cut;
+ if (count<=0) break;
+ }
+ return target-uar+1;
+ } /* decShiftToLeast */
+
+#if DECSUBSET
+/* ------------------------------------------------------------------ */
+/* decRoundOperand -- round an operand [used for subset only] */
+/* */
+/* dn is the number to round (dn->digits is > set->digits) */
+/* set is the relevant context */
+/* status is the status accumulator */
+/* */
+/* returns an allocated decNumber with the rounded result. */
+/* */
+/* lostDigits and other status may be set by this. */
+/* */
+/* Since the input is an operand, it must not be modified. */
+/* Instead, return an allocated decNumber, rounded as required. */
+/* It is the caller's responsibility to free the allocated storage. */
+/* */
+/* If no storage is available then the result cannot be used, so NULL */
+/* is returned. */
+/* ------------------------------------------------------------------ */
+static decNumber *decRoundOperand(const decNumber *dn, decContext *set,
+ uInt *status) {
+ decNumber *res; /* result structure */
+ uInt newstatus=0; /* status from round */
+ Int residue=0; /* rounding accumulator */
+
+ /* Allocate storage for the returned decNumber, big enough for the */
+ /* length specified by the context */
+ res=(decNumber *)malloc(sizeof(decNumber)
+ +(D2U(set->digits)-1)*sizeof(Unit));
+ if (res==NULL) {
+ *status|=DEC_Insufficient_storage;
+ return NULL;
+ }
+ decCopyFit(res, dn, set, &residue, &newstatus);
+ decApplyRound(res, set, residue, &newstatus);
+
+ /* If that set Inexact then "lost digits" is raised... */
+ if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits;
+ *status|=newstatus;
+ return res;
+ } /* decRoundOperand */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decCopyFit -- copy a number, truncating the coefficient if needed */
+/* */
+/* dest is the target decNumber */
+/* src is the source decNumber */
+/* set is the context [used for length (digits) and rounding mode] */
+/* residue is the residue accumulator */
+/* status contains the current status to be updated */
+/* */
+/* (dest==src is allowed and will be a no-op if fits) */
+/* All fields are updated as required. */
+/* ------------------------------------------------------------------ */
+static void decCopyFit(decNumber *dest, const decNumber *src,
+ decContext *set, Int *residue, uInt *status) {
+ dest->bits=src->bits;
+ dest->exponent=src->exponent;
+ decSetCoeff(dest, set, src->lsu, src->digits, residue, status);
+ } /* decCopyFit */
+
+/* ------------------------------------------------------------------ */
+/* decSetCoeff -- set the coefficient of a number */
+/* */
+/* dn is the number whose coefficient array is to be set. */
+/* It must have space for set->digits digits */
+/* set is the context [for size] */
+/* lsu -> lsu of the source coefficient [may be dn->lsu] */
+/* len is digits in the source coefficient [may be dn->digits] */
+/* residue is the residue accumulator. This has values as in */
+/* decApplyRound, and will be unchanged unless the */
+/* target size is less than len. In this case, the */
+/* coefficient is truncated and the residue is updated to */
+/* reflect the previous residue and the dropped digits. */
+/* status is the status accumulator, as usual */
+/* */
+/* The coefficient may already be in the number, or it can be an */
+/* external intermediate array. If it is in the number, lsu must == */
+/* dn->lsu and len must == dn->digits. */
+/* */
+/* Note that the coefficient length (len) may be < set->digits, and */
+/* in this case this merely copies the coefficient (or is a no-op */
+/* if dn->lsu==lsu). */
+/* */
+/* Note also that (only internally, from decQuantizeOp and */
+/* decSetSubnormal) the value of set->digits may be less than one, */
+/* indicating a round to left. This routine handles that case */
+/* correctly; caller ensures space. */
+/* */
+/* dn->digits, dn->lsu (and as required), and dn->exponent are */
+/* updated as necessary. dn->bits (sign) is unchanged. */
+/* */
+/* DEC_Rounded status is set if any digits are discarded. */
+/* DEC_Inexact status is set if any non-zero digits are discarded, or */
+/* incoming residue was non-0 (implies rounded) */
+/* ------------------------------------------------------------------ */
+/* mapping array: maps 0-9 to canonical residues, so that a residue */
+/* can be adjusted in the range [-1, +1] and achieve correct rounding */
+/* 0 1 2 3 4 5 6 7 8 9 */
+static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7};
+static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu,
+ Int len, Int *residue, uInt *status) {
+ Int discard; /* number of digits to discard */
+ uInt cut; /* cut point in Unit */
+ const Unit *up; /* work */
+ Unit *target; /* .. */
+ Int count; /* .. */
+ #if DECDPUN<=4
+ uInt temp; /* .. */
+ #endif
+
+ discard=len-set->digits; /* digits to discard */
+ if (discard<=0) { /* no digits are being discarded */
+ if (dn->lsu!=lsu) { /* copy needed */
+ /* copy the coefficient array to the result number; no shift needed */
+ count=len; /* avoids D2U */
+ up=lsu;
+ for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
+ *target=*up;
+ dn->digits=len; /* set the new length */
+ }
+ /* dn->exponent and residue are unchanged, record any inexactitude */
+ if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded);
+ return;
+ }
+
+ /* some digits must be discarded ... */
+ dn->exponent+=discard; /* maintain numerical value */
+ *status|=DEC_Rounded; /* accumulate Rounded status */
+ if (*residue>1) *residue=1; /* previous residue now to right, so reduce */
+
+ if (discard>len) { /* everything, +1, is being discarded */
+ /* guard digit is 0 */
+ /* residue is all the number [NB could be all 0s] */
+ if (*residue<=0) { /* not already positive */
+ count=len; /* avoids D2U */
+ for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { /* found non-0 */
+ *residue=1;
+ break; /* no need to check any others */
+ }
+ }
+ if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
+ *dn->lsu=0; /* coefficient will now be 0 */
+ dn->digits=1; /* .. */
+ return;
+ } /* total discard */
+
+ /* partial discard [most common case] */
+ /* here, at least the first (most significant) discarded digit exists */
+
+ /* spin up the number, noting residue during the spin, until get to */
+ /* the Unit with the first discarded digit. When reach it, extract */
+ /* it and remember its position */
+ count=0;
+ for (up=lsu;; up++) {
+ count+=DECDPUN;
+ if (count>=discard) break; /* full ones all checked */
+ if (*up!=0) *residue=1;
+ } /* up */
+
+ /* here up -> Unit with first discarded digit */
+ cut=discard-(count-DECDPUN)-1;
+ if (cut==DECDPUN-1) { /* unit-boundary case (fast) */
+ Unit half=(Unit)powers[DECDPUN]>>1;
+ /* set residue directly */
+ if (*up>=half) {
+ if (*up>half) *residue=7;
+ else *residue+=5; /* add sticky bit */
+ }
+ else { /* <half */
+ if (*up!=0) *residue=3; /* [else is 0, leave as sticky bit] */
+ }
+ if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
+ *dn->lsu=0; /* .. result is 0 */
+ dn->digits=1; /* .. */
+ }
+ else { /* shift to least */
+ count=set->digits; /* now digits to end up with */
+ dn->digits=count; /* set the new length */
+ up++; /* move to next */
+ /* on unit boundary, so shift-down copy loop is simple */
+ for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
+ *target=*up;
+ }
+ } /* unit-boundary case */
+
+ else { /* discard digit is in low digit(s), and not top digit */
+ uInt discard1; /* first discarded digit */
+ uInt quot, rem; /* for divisions */
+ if (cut==0) quot=*up; /* is at bottom of unit */
+ else /* cut>0 */ { /* it's not at bottom of unit */
+ #if DECDPUN<=4
+ quot=QUOT10(*up, cut);
+ rem=*up-quot*powers[cut];
+ #else
+ rem=*up%powers[cut];
+ quot=*up/powers[cut];
+ #endif
+ if (rem!=0) *residue=1;
+ }
+ /* discard digit is now at bottom of quot */
+ #if DECDPUN<=4
+ temp=(quot*6554)>>16; /* fast /10 */
+ /* Vowels algorithm here not a win (9 instructions) */
+ discard1=quot-X10(temp);
+ quot=temp;
+ #else
+ discard1=quot%10;
+ quot=quot/10;
+ #endif
+ /* here, discard1 is the guard digit, and residue is everything */
+ /* else [use mapping array to accumulate residue safely] */
+ *residue+=resmap[discard1];
+ cut++; /* update cut */
+ /* here: up -> Unit of the array with bottom digit */
+ /* cut is the division point for each Unit */
+ /* quot holds the uncut high-order digits for the current unit */
+ if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
+ *dn->lsu=0; /* .. result is 0 */
+ dn->digits=1; /* .. */
+ }
+ else { /* shift to least needed */
+ count=set->digits; /* now digits to end up with */
+ dn->digits=count; /* set the new length */
+ /* shift-copy the coefficient array to the result number */
+ for (target=dn->lsu; ; target++) {
+ *target=(Unit)quot;
+ count-=(DECDPUN-cut);
+ if (count<=0) break;
+ up++;
+ quot=*up;
+ #if DECDPUN<=4
+ quot=QUOT10(quot, cut);
+ rem=*up-quot*powers[cut];
+ #else
+ rem=quot%powers[cut];
+ quot=quot/powers[cut];
+ #endif
+ *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
+ count-=cut;
+ if (count<=0) break;
+ } /* shift-copy loop */
+ } /* shift to least */
+ } /* not unit boundary */
+
+ if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
+ return;
+ } /* decSetCoeff */
+
+/* ------------------------------------------------------------------ */
+/* decApplyRound -- apply pending rounding to a number */
+/* */
+/* dn is the number, with space for set->digits digits */
+/* set is the context [for size and rounding mode] */
+/* residue indicates pending rounding, being any accumulated */
+/* guard and sticky information. It may be: */
+/* 6-9: rounding digit is >5 */
+/* 5: rounding digit is exactly half-way */
+/* 1-4: rounding digit is <5 and >0 */
+/* 0: the coefficient is exact */
+/* -1: as 1, but the hidden digits are subtractive, that */
+/* is, of the opposite sign to dn. In this case the */
+/* coefficient must be non-0. This case occurs when */
+/* subtracting a small number (which can be reduced to */
+/* a sticky bit); see decAddOp. */
+/* status is the status accumulator, as usual */
+/* */
+/* This routine applies rounding while keeping the length of the */
+/* coefficient constant. The exponent and status are unchanged */
+/* except if: */
+/* */
+/* -- the coefficient was increased and is all nines (in which */
+/* case Overflow could occur, and is handled directly here so */
+/* the caller does not need to re-test for overflow) */
+/* */
+/* -- the coefficient was decreased and becomes all nines (in which */
+/* case Underflow could occur, and is also handled directly). */
+/* */
+/* All fields in dn are updated as required. */
+/* */
+/* ------------------------------------------------------------------ */
+static void decApplyRound(decNumber *dn, decContext *set, Int residue,
+ uInt *status) {
+ Int bump; /* 1 if coefficient needs to be incremented */
+ /* -1 if coefficient needs to be decremented */
+
+ if (residue==0) return; /* nothing to apply */
+
+ bump=0; /* assume a smooth ride */
+
+ /* now decide whether, and how, to round, depending on mode */
+ switch (set->round) {
+ case DEC_ROUND_05UP: { /* round zero or five up (for reround) */
+ /* This is the same as DEC_ROUND_DOWN unless there is a */
+ /* positive residue and the lsd of dn is 0 or 5, in which case */
+ /* it is bumped; when residue is <0, the number is therefore */
+ /* bumped down unless the final digit was 1 or 6 (in which */
+ /* case it is bumped down and then up -- a no-op) */
+ Int lsd5=*dn->lsu%5; /* get lsd and quintate */
+ if (residue<0 && lsd5!=1) bump=-1;
+ else if (residue>0 && lsd5==0) bump=1;
+ /* [bump==1 could be applied directly; use common path for clarity] */
+ break;} /* r-05 */
+
+ case DEC_ROUND_DOWN: {
+ /* no change, except if negative residue */
+ if (residue<0) bump=-1;
+ break;} /* r-d */
+
+ case DEC_ROUND_HALF_DOWN: {
+ if (residue>5) bump=1;
+ break;} /* r-h-d */
+
+ case DEC_ROUND_HALF_EVEN: {
+ if (residue>5) bump=1; /* >0.5 goes up */
+ else if (residue==5) { /* exactly 0.5000... */
+ /* 0.5 goes up iff [new] lsd is odd */
+ if (*dn->lsu & 0x01) bump=1;
+ }
+ break;} /* r-h-e */
+
+ case DEC_ROUND_HALF_UP: {
+ if (residue>=5) bump=1;
+ break;} /* r-h-u */
+
+ case DEC_ROUND_UP: {
+ if (residue>0) bump=1;
+ break;} /* r-u */
+
+ case DEC_ROUND_CEILING: {
+ /* same as _UP for positive numbers, and as _DOWN for negatives */
+ /* [negative residue cannot occur on 0] */
+ if (decNumberIsNegative(dn)) {
+ if (residue<0) bump=-1;
+ }
+ else {
+ if (residue>0) bump=1;
+ }
+ break;} /* r-c */
+
+ case DEC_ROUND_FLOOR: {
+ /* same as _UP for negative numbers, and as _DOWN for positive */
+ /* [negative residue cannot occur on 0] */
+ if (!decNumberIsNegative(dn)) {
+ if (residue<0) bump=-1;
+ }
+ else {
+ if (residue>0) bump=1;
+ }
+ break;} /* r-f */
+
+ default: { /* e.g., DEC_ROUND_MAX */
+ *status|=DEC_Invalid_context;
+ #if DECTRACE || (DECCHECK && DECVERB)
+ printf("Unknown rounding mode: %d\n", set->round);
+ #endif
+ break;}
+ } /* switch */
+
+ /* now bump the number, up or down, if need be */
+ if (bump==0) return; /* no action required */
+
+ /* Simply use decUnitAddSub unless bumping up and the number is */
+ /* all nines. In this special case set to 100... explicitly */
+ /* and adjust the exponent by one (as otherwise could overflow */
+ /* the array) */
+ /* Similarly handle all-nines result if bumping down. */
+ if (bump>0) {
+ Unit *up; /* work */
+ uInt count=dn->digits; /* digits to be checked */
+ for (up=dn->lsu; ; up++) {
+ if (count<=DECDPUN) {
+ /* this is the last Unit (the msu) */
+ if (*up!=powers[count]-1) break; /* not still 9s */
+ /* here if it, too, is all nines */
+ *up=(Unit)powers[count-1]; /* here 999 -> 100 etc. */
+ for (up=up-1; up>=dn->lsu; up--) *up=0; /* others all to 0 */
+ dn->exponent++; /* and bump exponent */
+ /* [which, very rarely, could cause Overflow...] */
+ if ((dn->exponent+dn->digits)>set->emax+1) {
+ decSetOverflow(dn, set, status);
+ }
+ return; /* done */
+ }
+ /* a full unit to check, with more to come */
+ if (*up!=DECDPUNMAX) break; /* not still 9s */
+ count-=DECDPUN;
+ } /* up */
+ } /* bump>0 */
+ else { /* -1 */
+ /* here checking for a pre-bump of 1000... (leading 1, all */
+ /* other digits zero) */
+ Unit *up, *sup; /* work */
+ uInt count=dn->digits; /* digits to be checked */
+ for (up=dn->lsu; ; up++) {
+ if (count<=DECDPUN) {
+ /* this is the last Unit (the msu) */
+ if (*up!=powers[count-1]) break; /* not 100.. */
+ /* here if have the 1000... case */
+ sup=up; /* save msu pointer */
+ *up=(Unit)powers[count]-1; /* here 100 in msu -> 999 */
+ /* others all to all-nines, too */
+ for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1;
+ dn->exponent--; /* and bump exponent */
+
+ /* iff the number was at the subnormal boundary (exponent=etiny) */
+ /* then the exponent is now out of range, so it will in fact get */
+ /* clamped to etiny and the final 9 dropped. */
+ /* printf(">> emin=%d exp=%d sdig=%d\n", set->emin, */
+ /* dn->exponent, set->digits); */
+ if (dn->exponent+1==set->emin-set->digits+1) {
+ if (count==1 && dn->digits==1) *sup=0; /* here 9 -> 0[.9] */
+ else {
+ *sup=(Unit)powers[count-1]-1; /* here 999.. in msu -> 99.. */
+ dn->digits--;
+ }
+ dn->exponent++;
+ *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
+ }
+ return; /* done */
+ }
+
+ /* a full unit to check, with more to come */
+ if (*up!=0) break; /* not still 0s */
+ count-=DECDPUN;
+ } /* up */
+
+ } /* bump<0 */
+
+ /* Actual bump needed. Do it. */
+ decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump);
+ } /* decApplyRound */
+
+#if DECSUBSET
+/* ------------------------------------------------------------------ */
+/* decFinish -- finish processing a number */
+/* */
+/* dn is the number */
+/* set is the context */
+/* residue is the rounding accumulator (as in decApplyRound) */
+/* status is the accumulator */
+/* */
+/* This finishes off the current number by: */
+/* 1. If not extended: */
+/* a. Converting a zero result to clean '0' */
+/* b. Reducing positive exponents to 0, if would fit in digits */
+/* 2. Checking for overflow and subnormals (always) */
+/* Note this is just Finalize when no subset arithmetic. */
+/* All fields are updated as required. */
+/* ------------------------------------------------------------------ */
+static void decFinish(decNumber *dn, decContext *set, Int *residue,
+ uInt *status) {
+ if (!set->extended) {
+ if ISZERO(dn) { /* value is zero */
+ dn->exponent=0; /* clean exponent .. */
+ dn->bits=0; /* .. and sign */
+ return; /* no error possible */
+ }
+ if (dn->exponent>=0) { /* non-negative exponent */
+ /* >0; reduce to integer if possible */
+ if (set->digits >= (dn->exponent+dn->digits)) {
+ dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent);
+ dn->exponent=0;
+ }
+ }
+ } /* !extended */
+
+ decFinalize(dn, set, residue, status);
+ } /* decFinish */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decFinalize -- final check, clamp, and round of a number */
+/* */
+/* dn is the number */
+/* set is the context */
+/* residue is the rounding accumulator (as in decApplyRound) */
+/* status is the status accumulator */
+/* */
+/* This finishes off the current number by checking for subnormal */
+/* results, applying any pending rounding, checking for overflow, */
+/* and applying any clamping. */
+/* Underflow and overflow conditions are raised as appropriate. */
+/* All fields are updated as required. */
+/* ------------------------------------------------------------------ */
+static void decFinalize(decNumber *dn, decContext *set, Int *residue,
+ uInt *status) {
+ Int shift; /* shift needed if clamping */
+ Int tinyexp=set->emin-dn->digits+1; /* precalculate subnormal boundary */
+
+ /* Must be careful, here, when checking the exponent as the */
+ /* adjusted exponent could overflow 31 bits [because it may already */
+ /* be up to twice the expected]. */
+
+ /* First test for subnormal. This must be done before any final */
+ /* round as the result could be rounded to Nmin or 0. */
+ if (dn->exponent<=tinyexp) { /* prefilter */
+ Int comp;
+ decNumber nmin;
+ /* A very nasty case here is dn == Nmin and residue<0 */
+ if (dn->exponent<tinyexp) {
+ /* Go handle subnormals; this will apply round if needed. */
+ decSetSubnormal(dn, set, residue, status);
+ return;
+ }
+ /* Equals case: only subnormal if dn=Nmin and negative residue */
+ uprv_decNumberZero(&nmin);
+ nmin.lsu[0]=1;
+ nmin.exponent=set->emin;
+ comp=decCompare(dn, &nmin, 1); /* (signless compare) */
+ if (comp==BADINT) { /* oops */
+ *status|=DEC_Insufficient_storage; /* abandon... */
+ return;
+ }
+ if (*residue<0 && comp==0) { /* neg residue and dn==Nmin */
+ decApplyRound(dn, set, *residue, status); /* might force down */
+ decSetSubnormal(dn, set, residue, status);
+ return;
+ }
+ }
+
+ /* now apply any pending round (this could raise overflow). */
+ if (*residue!=0) decApplyRound(dn, set, *residue, status);
+
+ /* Check for overflow [redundant in the 'rare' case] or clamp */
+ if (dn->exponent<=set->emax-set->digits+1) return; /* neither needed */
+
+
+ /* here when might have an overflow or clamp to do */
+ if (dn->exponent>set->emax-dn->digits+1) { /* too big */
+ decSetOverflow(dn, set, status);
+ return;
+ }
+ /* here when the result is normal but in clamp range */
+ if (!set->clamp) return;
+
+ /* here when need to apply the IEEE exponent clamp (fold-down) */
+ shift=dn->exponent-(set->emax-set->digits+1);
+
+ /* shift coefficient (if non-zero) */
+ if (!ISZERO(dn)) {
+ dn->digits=decShiftToMost(dn->lsu, dn->digits, shift);
+ }
+ dn->exponent-=shift; /* adjust the exponent to match */
+ *status|=DEC_Clamped; /* and record the dirty deed */
+ return;
+ } /* decFinalize */
+
+/* ------------------------------------------------------------------ */
+/* decSetOverflow -- set number to proper overflow value */
+/* */
+/* dn is the number (used for sign [only] and result) */
+/* set is the context [used for the rounding mode, etc.] */
+/* status contains the current status to be updated */
+/* */
+/* This sets the sign of a number and sets its value to either */
+/* Infinity or the maximum finite value, depending on the sign of */
+/* dn and the rounding mode, following IEEE 754 rules. */
+/* ------------------------------------------------------------------ */
+static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) {
+ Flag needmax=0; /* result is maximum finite value */
+ uByte sign=dn->bits&DECNEG; /* clean and save sign bit */
+
+ if (ISZERO(dn)) { /* zero does not overflow magnitude */
+ Int emax=set->emax; /* limit value */
+ if (set->clamp) emax-=set->digits-1; /* lower if clamping */
+ if (dn->exponent>emax) { /* clamp required */
+ dn->exponent=emax;
+ *status|=DEC_Clamped;
+ }
+ return;
+ }
+
+ uprv_decNumberZero(dn);
+ switch (set->round) {
+ case DEC_ROUND_DOWN: {
+ needmax=1; /* never Infinity */
+ break;} /* r-d */
+ case DEC_ROUND_05UP: {
+ needmax=1; /* never Infinity */
+ break;} /* r-05 */
+ case DEC_ROUND_CEILING: {
+ if (sign) needmax=1; /* Infinity if non-negative */
+ break;} /* r-c */
+ case DEC_ROUND_FLOOR: {
+ if (!sign) needmax=1; /* Infinity if negative */
+ break;} /* r-f */
+ default: break; /* Infinity in all other cases */
+ }
+ if (needmax) {
+ decSetMaxValue(dn, set);
+ dn->bits=sign; /* set sign */
+ }
+ else dn->bits=sign|DECINF; /* Value is +/-Infinity */
+ *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded;
+ } /* decSetOverflow */
+
+/* ------------------------------------------------------------------ */
+/* decSetMaxValue -- set number to +Nmax (maximum normal value) */
+/* */
+/* dn is the number to set */
+/* set is the context [used for digits and emax] */
+/* */
+/* This sets the number to the maximum positive value. */
+/* ------------------------------------------------------------------ */
+static void decSetMaxValue(decNumber *dn, decContext *set) {
+ Unit *up; /* work */
+ Int count=set->digits; /* nines to add */
+ dn->digits=count;
+ /* fill in all nines to set maximum value */
+ for (up=dn->lsu; ; up++) {
+ if (count>DECDPUN) *up=DECDPUNMAX; /* unit full o'nines */
+ else { /* this is the msu */
+ *up=(Unit)(powers[count]-1);
+ break;
+ }
+ count-=DECDPUN; /* filled those digits */
+ } /* up */
+ dn->bits=0; /* + sign */
+ dn->exponent=set->emax-set->digits+1;
+ } /* decSetMaxValue */
+
+/* ------------------------------------------------------------------ */
+/* decSetSubnormal -- process value whose exponent is <Emin */
+/* */
+/* dn is the number (used as input as well as output; it may have */
+/* an allowed subnormal value, which may need to be rounded) */
+/* set is the context [used for the rounding mode] */
+/* residue is any pending residue */
+/* status contains the current status to be updated */
+/* */
+/* If subset mode, set result to zero and set Underflow flags. */
+/* */
+/* Value may be zero with a low exponent; this does not set Subnormal */
+/* but the exponent will be clamped to Etiny. */
+/* */
+/* Otherwise ensure exponent is not out of range, and round as */
+/* necessary. Underflow is set if the result is Inexact. */
+/* ------------------------------------------------------------------ */
+static void decSetSubnormal(decNumber *dn, decContext *set, Int *residue,
+ uInt *status) {
+ decContext workset; /* work */
+ Int etiny, adjust; /* .. */
+
+ #if DECSUBSET
+ /* simple set to zero and 'hard underflow' for subset */
+ if (!set->extended) {
+ uprv_decNumberZero(dn);
+ /* always full overflow */
+ *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
+ return;
+ }
+ #endif
+
+ /* Full arithmetic -- allow subnormals, rounded to minimum exponent */
+ /* (Etiny) if needed */
+ etiny=set->emin-(set->digits-1); /* smallest allowed exponent */
+
+ if ISZERO(dn) { /* value is zero */
+ /* residue can never be non-zero here */
+ #if DECCHECK
+ if (*residue!=0) {
+ printf("++ Subnormal 0 residue %ld\n", (LI)*residue);
+ *status|=DEC_Invalid_operation;
+ }
+ #endif
+ if (dn->exponent<etiny) { /* clamp required */
+ dn->exponent=etiny;
+ *status|=DEC_Clamped;
+ }
+ return;
+ }
+
+ *status|=DEC_Subnormal; /* have a non-zero subnormal */
+ adjust=etiny-dn->exponent; /* calculate digits to remove */
+ if (adjust<=0) { /* not out of range; unrounded */
+ /* residue can never be non-zero here, except in the Nmin-residue */
+ /* case (which is a subnormal result), so can take fast-path here */
+ /* it may already be inexact (from setting the coefficient) */
+ if (*status&DEC_Inexact) *status|=DEC_Underflow;
+ return;
+ }
+
+ /* adjust>0, so need to rescale the result so exponent becomes Etiny */
+ /* [this code is similar to that in rescale] */
+ workset=*set; /* clone rounding, etc. */
+ workset.digits=dn->digits-adjust; /* set requested length */
+ workset.emin-=adjust; /* and adjust emin to match */
+ /* [note that the latter can be <1, here, similar to Rescale case] */
+ decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status);
+ decApplyRound(dn, &workset, *residue, status);
+
+ /* Use 754 default rule: Underflow is set iff Inexact */
+ /* [independent of whether trapped] */
+ if (*status&DEC_Inexact) *status|=DEC_Underflow;
+
+ /* if rounded up a 999s case, exponent will be off by one; adjust */
+ /* back if so [it will fit, because it was shortened earlier] */
+ if (dn->exponent>etiny) {
+ dn->digits=decShiftToMost(dn->lsu, dn->digits, 1);
+ dn->exponent--; /* (re)adjust the exponent. */
+ }
+
+ /* if rounded to zero, it is by definition clamped... */
+ if (ISZERO(dn)) *status|=DEC_Clamped;
+ } /* decSetSubnormal */
+
+/* ------------------------------------------------------------------ */
+/* decCheckMath - check entry conditions for a math function */
+/* */
+/* This checks the context and the operand */
+/* */
+/* rhs is the operand to check */
+/* set is the context to check */
+/* status is unchanged if both are good */
+/* */
+/* returns non-zero if status is changed, 0 otherwise */
+/* */
+/* Restrictions enforced: */
+/* */
+/* digits, emax, and -emin in the context must be less than */
+/* DEC_MAX_MATH (999999), and A must be within these bounds if */
+/* non-zero. Invalid_operation is set in the status if a */
+/* restriction is violated. */
+/* ------------------------------------------------------------------ */
+static uInt decCheckMath(const decNumber *rhs, decContext *set,
+ uInt *status) {
+ uInt save=*status; /* record */
+ if (set->digits>DEC_MAX_MATH
+ || set->emax>DEC_MAX_MATH
+ || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context;
+ else if ((rhs->digits>DEC_MAX_MATH
+ || rhs->exponent+rhs->digits>DEC_MAX_MATH+1
+ || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH))
+ && !ISZERO(rhs)) *status|=DEC_Invalid_operation;
+ return (*status!=save);
+ } /* decCheckMath */
+
+/* ------------------------------------------------------------------ */
+/* decGetInt -- get integer from a number */
+/* */
+/* dn is the number [which will not be altered] */
+/* */
+/* returns one of: */
+/* BADINT if there is a non-zero fraction */
+/* the converted integer */
+/* BIGEVEN if the integer is even and magnitude > 2*10**9 */
+/* BIGODD if the integer is odd and magnitude > 2*10**9 */
+/* */
+/* This checks and gets a whole number from the input decNumber. */
+/* The sign can be determined from dn by the caller when BIGEVEN or */
+/* BIGODD is returned. */
+/* ------------------------------------------------------------------ */
+static Int decGetInt(const decNumber *dn) {
+ Int theInt; /* result accumulator */
+ const Unit *up; /* work */
+ Int got; /* digits (real or not) processed */
+ Int ilength=dn->digits+dn->exponent; /* integral length */
+ Flag neg=decNumberIsNegative(dn); /* 1 if -ve */
+
+ /* The number must be an integer that fits in 10 digits */
+ /* Assert, here, that 10 is enough for any rescale Etiny */
+ #if DEC_MAX_EMAX > 999999999
+ #error GetInt may need updating [for Emax]
+ #endif
+ #if DEC_MIN_EMIN < -999999999
+ #error GetInt may need updating [for Emin]
+ #endif
+ if (ISZERO(dn)) return 0; /* zeros are OK, with any exponent */
+
+ up=dn->lsu; /* ready for lsu */
+ theInt=0; /* ready to accumulate */
+ if (dn->exponent>=0) { /* relatively easy */
+ /* no fractional part [usual]; allow for positive exponent */
+ got=dn->exponent;
+ }
+ else { /* -ve exponent; some fractional part to check and discard */
+ Int count=-dn->exponent; /* digits to discard */
+ /* spin up whole units until reach the Unit with the unit digit */
+ for (; count>=DECDPUN; up++) {
+ if (*up!=0) return BADINT; /* non-zero Unit to discard */
+ count-=DECDPUN;
+ }
+ if (count==0) got=0; /* [a multiple of DECDPUN] */
+ else { /* [not multiple of DECDPUN] */
+ Int rem; /* work */
+ /* slice off fraction digits and check for non-zero */
+ #if DECDPUN<=4
+ theInt=QUOT10(*up, count);
+ rem=*up-theInt*powers[count];
+ #else
+ rem=*up%powers[count]; /* slice off discards */
+ theInt=*up/powers[count];
+ #endif
+ if (rem!=0) return BADINT; /* non-zero fraction */
+ /* it looks good */
+ got=DECDPUN-count; /* number of digits so far */
+ up++; /* ready for next */
+ }
+ }
+ /* now it's known there's no fractional part */
+
+ /* tricky code now, to accumulate up to 9.3 digits */
+ if (got==0) {theInt=*up; got+=DECDPUN; up++;} /* ensure lsu is there */
+
+ if (ilength<11) {
+ Int save=theInt;
+ /* collect any remaining unit(s) */
+ for (; got<ilength; up++) {
+ theInt+=*up*powers[got];
+ got+=DECDPUN;
+ }
+ if (ilength==10) { /* need to check for wrap */
+ if (theInt/(Int)powers[got-DECDPUN]!=(Int)*(up-1)) ilength=11;
+ /* [that test also disallows the BADINT result case] */
+ else if (neg && theInt>1999999997) ilength=11;
+ else if (!neg && theInt>999999999) ilength=11;
+ if (ilength==11) theInt=save; /* restore correct low bit */
+ }
+ }
+
+ if (ilength>10) { /* too big */
+ if (theInt&1) return BIGODD; /* bottom bit 1 */
+ return BIGEVEN; /* bottom bit 0 */
+ }
+
+ if (neg) theInt=-theInt; /* apply sign */
+ return theInt;
+ } /* decGetInt */
+
+/* ------------------------------------------------------------------ */
+/* decDecap -- decapitate the coefficient of a number */
+/* */
+/* dn is the number to be decapitated */
+/* drop is the number of digits to be removed from the left of dn; */
+/* this must be <= dn->digits (if equal, the coefficient is */
+/* set to 0) */
+/* */
+/* Returns dn; dn->digits will be <= the initial digits less drop */
+/* (after removing drop digits there may be leading zero digits */
+/* which will also be removed). Only dn->lsu and dn->digits change. */
+/* ------------------------------------------------------------------ */
+static decNumber *decDecap(decNumber *dn, Int drop) {
+ Unit *msu; /* -> target cut point */
+ Int cut; /* work */
+ if (drop>=dn->digits) { /* losing the whole thing */
+ #if DECCHECK
+ if (drop>dn->digits)
+ printf("decDecap called with drop>digits [%ld>%ld]\n",
+ (LI)drop, (LI)dn->digits);
+ #endif
+ dn->lsu[0]=0;
+ dn->digits=1;
+ return dn;
+ }
+ msu=dn->lsu+D2U(dn->digits-drop)-1; /* -> likely msu */
+ cut=MSUDIGITS(dn->digits-drop); /* digits to be in use in msu */
+ if (cut!=DECDPUN) *msu%=powers[cut]; /* clear left digits */
+ /* that may have left leading zero digits, so do a proper count... */
+ dn->digits=decGetDigits(dn->lsu, msu-dn->lsu+1);
+ return dn;
+ } /* decDecap */
+
+/* ------------------------------------------------------------------ */
+/* decBiStr -- compare string with pairwise options */
+/* */
+/* targ is the string to compare */
+/* str1 is one of the strings to compare against (length may be 0) */
+/* str2 is the other; it must be the same length as str1 */
+/* */
+/* returns 1 if strings compare equal, (that is, it is the same */
+/* length as str1 and str2, and each character of targ is in either */
+/* str1 or str2 in the corresponding position), or 0 otherwise */
+/* */
+/* This is used for generic caseless compare, including the awkward */
+/* case of the Turkish dotted and dotless Is. Use as (for example): */
+/* if (decBiStr(test, "mike", "MIKE")) ... */
+/* ------------------------------------------------------------------ */
+static Flag decBiStr(const char *targ, const char *str1, const char *str2) {
+ for (;;targ++, str1++, str2++) {
+ if (*targ!=*str1 && *targ!=*str2) return 0;
+ /* *targ has a match in one (or both, if terminator) */
+ if (*targ=='\0') break;
+ } /* forever */
+ return 1;
+ } /* decBiStr */
+
+/* ------------------------------------------------------------------ */
+/* decNaNs -- handle NaN operand or operands */
+/* */
+/* res is the result number */
+/* lhs is the first operand */
+/* rhs is the second operand, or NULL if none */
+/* context is used to limit payload length */
+/* status contains the current status */
+/* returns res in case convenient */
+/* */
+/* Called when one or both operands is a NaN, and propagates the */
+/* appropriate result to res. When an sNaN is found, it is changed */
+/* to a qNaN and Invalid operation is set. */
+/* ------------------------------------------------------------------ */
+static decNumber * decNaNs(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ uInt *status) {
+ /* This decision tree ends up with LHS being the source pointer, */
+ /* and status updated if need be */
+ if (lhs->bits & DECSNAN)
+ *status|=DEC_Invalid_operation | DEC_sNaN;
+ else if (rhs==NULL);
+ else if (rhs->bits & DECSNAN) {
+ lhs=rhs;
+ *status|=DEC_Invalid_operation | DEC_sNaN;
+ }
+ else if (lhs->bits & DECNAN);
+ else lhs=rhs;
+
+ /* propagate the payload */
+ if (lhs->digits<=set->digits) uprv_decNumberCopy(res, lhs); /* easy */
+ else { /* too long */
+ const Unit *ul;
+ Unit *ur, *uresp1;
+ /* copy safe number of units, then decapitate */
+ res->bits=lhs->bits; /* need sign etc. */
+ uresp1=res->lsu+D2U(set->digits);
+ for (ur=res->lsu, ul=lhs->lsu; ur<uresp1; ur++, ul++) *ur=*ul;
+ res->digits=D2U(set->digits)*DECDPUN;
+ /* maybe still too long */
+ if (res->digits>set->digits) decDecap(res, res->digits-set->digits);
+ }
+
+ res->bits&=~DECSNAN; /* convert any sNaN to NaN, while */
+ res->bits|=DECNAN; /* .. preserving sign */
+ res->exponent=0; /* clean exponent */
+ /* [coefficient was copied/decapitated] */
+ return res;
+ } /* decNaNs */
+
+/* ------------------------------------------------------------------ */
+/* decStatus -- apply non-zero status */
+/* */
+/* dn is the number to set if error */
+/* status contains the current status (not yet in context) */
+/* set is the context */
+/* */
+/* If the status is an error status, the number is set to a NaN, */
+/* unless the error was an overflow, divide-by-zero, or underflow, */
+/* in which case the number will have already been set. */
+/* */
+/* The context status is then updated with the new status. Note that */
+/* this may raise a signal, so control may never return from this */
+/* routine (hence resources must be recovered before it is called). */
+/* ------------------------------------------------------------------ */
+static void decStatus(decNumber *dn, uInt status, decContext *set) {
+ if (status & DEC_NaNs) { /* error status -> NaN */
+ /* if cause was an sNaN, clear and propagate [NaN is already set up] */
+ if (status & DEC_sNaN) status&=~DEC_sNaN;
+ else {
+ uprv_decNumberZero(dn); /* other error: clean throughout */
+ dn->bits=DECNAN; /* and make a quiet NaN */
+ }
+ }
+ uprv_decContextSetStatus(set, status); /* [may not return] */
+ return;
+ } /* decStatus */
+
+/* ------------------------------------------------------------------ */
+/* decGetDigits -- count digits in a Units array */
+/* */
+/* uar is the Unit array holding the number (this is often an */
+/* accumulator of some sort) */
+/* len is the length of the array in units [>=1] */
+/* */
+/* returns the number of (significant) digits in the array */
+/* */
+/* All leading zeros are excluded, except the last if the array has */
+/* only zero Units. */
+/* ------------------------------------------------------------------ */
+/* This may be called twice during some operations. */
+static Int decGetDigits(Unit *uar, Int len) {
+ Unit *up=uar+(len-1); /* -> msu */
+ Int digits=(len-1)*DECDPUN+1; /* possible digits excluding msu */
+ #if DECDPUN>4
+ uInt const *pow; /* work */
+ #endif
+ /* (at least 1 in final msu) */
+ #if DECCHECK
+ if (len<1) printf("decGetDigits called with len<1 [%ld]\n", (LI)len);
+ #endif
+
+ for (; up>=uar; up--) {
+ if (*up==0) { /* unit is all 0s */
+ if (digits==1) break; /* a zero has one digit */
+ digits-=DECDPUN; /* adjust for 0 unit */
+ continue;}
+ /* found the first (most significant) non-zero Unit */
+ #if DECDPUN>1 /* not done yet */
+ if (*up<10) break; /* is 1-9 */
+ digits++;
+ #if DECDPUN>2 /* not done yet */
+ if (*up<100) break; /* is 10-99 */
+ digits++;
+ #if DECDPUN>3 /* not done yet */
+ if (*up<1000) break; /* is 100-999 */
+ digits++;
+ #if DECDPUN>4 /* count the rest ... */
+ for (pow=&powers[4]; *up>=*pow; pow++) digits++;
+ #endif
+ #endif
+ #endif
+ #endif
+ break;
+ } /* up */
+ return digits;
+ } /* decGetDigits */
+
+#if DECTRACE | DECCHECK
+/* ------------------------------------------------------------------ */
+/* decNumberShow -- display a number [debug aid] */
+/* dn is the number to show */
+/* */
+/* Shows: sign, exponent, coefficient (msu first), digits */
+/* or: sign, special-value */
+/* ------------------------------------------------------------------ */
+/* this is public so other modules can use it */
+void uprv_decNumberShow(const decNumber *dn) {
+ const Unit *up; /* work */
+ uInt u, d; /* .. */
+ Int cut; /* .. */
+ char isign='+'; /* main sign */
+ if (dn==NULL) {
+ printf("NULL\n");
+ return;}
+ if (decNumberIsNegative(dn)) isign='-';
+ printf(" >> %c ", isign);
+ if (dn->bits&DECSPECIAL) { /* Is a special value */
+ if (decNumberIsInfinite(dn)) printf("Infinity");
+ else { /* a NaN */
+ if (dn->bits&DECSNAN) printf("sNaN"); /* signalling NaN */
+ else printf("NaN");
+ }
+ /* if coefficient and exponent are 0, no more to do */
+ if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) {
+ printf("\n");
+ return;}
+ /* drop through to report other information */
+ printf(" ");
+ }
+
+ /* now carefully display the coefficient */
+ up=dn->lsu+D2U(dn->digits)-1; /* msu */
+ printf("%ld", (LI)*up);
+ for (up=up-1; up>=dn->lsu; up--) {
+ u=*up;
+ printf(":");
+ for (cut=DECDPUN-1; cut>=0; cut--) {
+ d=u/powers[cut];
+ u-=d*powers[cut];
+ printf("%ld", (LI)d);
+ } /* cut */
+ } /* up */
+ if (dn->exponent!=0) {
+ char esign='+';
+ if (dn->exponent<0) esign='-';
+ printf(" E%c%ld", esign, (LI)abs(dn->exponent));
+ }
+ printf(" [%ld]\n", (LI)dn->digits);
+ } /* decNumberShow */
+#endif
+
+#if DECTRACE || DECCHECK
+/* ------------------------------------------------------------------ */
+/* decDumpAr -- display a unit array [debug/check aid] */
+/* name is a single-character tag name */
+/* ar is the array to display */
+/* len is the length of the array in Units */
+/* ------------------------------------------------------------------ */
+static void decDumpAr(char name, const Unit *ar, Int len) {
+ Int i;
+ const char *spec;
+ #if DECDPUN==9
+ spec="%09d ";
+ #elif DECDPUN==8
+ spec="%08d ";
+ #elif DECDPUN==7
+ spec="%07d ";
+ #elif DECDPUN==6
+ spec="%06d ";
+ #elif DECDPUN==5
+ spec="%05d ";
+ #elif DECDPUN==4
+ spec="%04d ";
+ #elif DECDPUN==3
+ spec="%03d ";
+ #elif DECDPUN==2
+ spec="%02d ";
+ #else
+ spec="%d ";
+ #endif
+ printf(" :%c: ", name);
+ for (i=len-1; i>=0; i--) {
+ if (i==len-1) printf("%ld ", (LI)ar[i]);
+ else printf(spec, ar[i]);
+ }
+ printf("\n");
+ return;}
+#endif
+
+#if DECCHECK
+/* ------------------------------------------------------------------ */
+/* decCheckOperands -- check operand(s) to a routine */
+/* res is the result structure (not checked; it will be set to */
+/* quiet NaN if error found (and it is not NULL)) */
+/* lhs is the first operand (may be DECUNRESU) */
+/* rhs is the second (may be DECUNUSED) */
+/* set is the context (may be DECUNCONT) */
+/* returns 0 if both operands, and the context are clean, or 1 */
+/* otherwise (in which case the context will show an error, */
+/* unless NULL). Note that res is not cleaned; caller should */
+/* handle this so res=NULL case is safe. */
+/* The caller is expected to abandon immediately if 1 is returned. */
+/* ------------------------------------------------------------------ */
+static Flag decCheckOperands(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ Flag bad=0;
+ if (set==NULL) { /* oops; hopeless */
+ #if DECTRACE || DECVERB
+ printf("Reference to context is NULL.\n");
+ #endif
+ bad=1;
+ return 1;}
+ else if (set!=DECUNCONT
+ && (set->digits<1 || set->round>=DEC_ROUND_MAX)) {
+ bad=1;
+ #if DECTRACE || DECVERB
+ printf("Bad context [digits=%ld round=%ld].\n",
+ (LI)set->digits, (LI)set->round);
+ #endif
+ }
+ else {
+ if (res==NULL) {
+ bad=1;
+ #if DECTRACE
+ /* this one not DECVERB as standard tests include NULL */
+ printf("Reference to result is NULL.\n");
+ #endif
+ }
+ if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs));
+ if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs));
+ }
+ if (bad) {
+ if (set!=DECUNCONT) uprv_decContextSetStatus(set, DEC_Invalid_operation);
+ if (res!=DECUNRESU && res!=NULL) {
+ uprv_decNumberZero(res);
+ res->bits=DECNAN; /* qNaN */
+ }
+ }
+ return bad;
+ } /* decCheckOperands */
+
+/* ------------------------------------------------------------------ */
+/* decCheckNumber -- check a number */
+/* dn is the number to check */
+/* returns 0 if the number is clean, or 1 otherwise */
+/* */
+/* The number is considered valid if it could be a result from some */
+/* operation in some valid context. */
+/* ------------------------------------------------------------------ */
+static Flag decCheckNumber(const decNumber *dn) {
+ const Unit *up; /* work */
+ uInt maxuint; /* .. */
+ Int ae, d, digits; /* .. */
+ Int emin, emax; /* .. */
+
+ if (dn==NULL) { /* hopeless */
+ #if DECTRACE
+ /* this one not DECVERB as standard tests include NULL */
+ printf("Reference to decNumber is NULL.\n");
+ #endif
+ return 1;}
+
+ /* check special values */
+ if (dn->bits & DECSPECIAL) {
+ if (dn->exponent!=0) {
+ #if DECTRACE || DECVERB
+ printf("Exponent %ld (not 0) for a special value [%02x].\n",
+ (LI)dn->exponent, dn->bits);
+ #endif
+ return 1;}
+
+ /* 2003.09.08: NaNs may now have coefficients, so next tests Inf only */
+ if (decNumberIsInfinite(dn)) {
+ if (dn->digits!=1) {
+ #if DECTRACE || DECVERB
+ printf("Digits %ld (not 1) for an infinity.\n", (LI)dn->digits);
+ #endif
+ return 1;}
+ if (*dn->lsu!=0) {
+ #if DECTRACE || DECVERB
+ printf("LSU %ld (not 0) for an infinity.\n", (LI)*dn->lsu);
+ #endif
+ decDumpAr('I', dn->lsu, D2U(dn->digits));
+ return 1;}
+ } /* Inf */
+ /* 2002.12.26: negative NaNs can now appear through proposed IEEE */
+ /* concrete formats (decimal64, etc.). */
+ return 0;
+ }
+
+ /* check the coefficient */
+ if (dn->digits<1 || dn->digits>DECNUMMAXP) {
+ #if DECTRACE || DECVERB
+ printf("Digits %ld in number.\n", (LI)dn->digits);
+ #endif
+ return 1;}
+
+ d=dn->digits;
+
+ for (up=dn->lsu; d>0; up++) {
+ if (d>DECDPUN) maxuint=DECDPUNMAX;
+ else { /* reached the msu */
+ maxuint=powers[d]-1;
+ if (dn->digits>1 && *up<powers[d-1]) {
+ #if DECTRACE || DECVERB
+ printf("Leading 0 in number.\n");
+ uprv_decNumberShow(dn);
+ #endif
+ return 1;}
+ }
+ if (*up>maxuint) {
+ #if DECTRACE || DECVERB
+ printf("Bad Unit [%08lx] in %ld-digit number at offset %ld [maxuint %ld].\n",
+ (LI)*up, (LI)dn->digits, (LI)(up-dn->lsu), (LI)maxuint);
+ #endif
+ return 1;}
+ d-=DECDPUN;
+ }
+
+ /* check the exponent. Note that input operands can have exponents */
+ /* which are out of the set->emin/set->emax and set->digits range */
+ /* (just as they can have more digits than set->digits). */
+ ae=dn->exponent+dn->digits-1; /* adjusted exponent */
+ emax=DECNUMMAXE;
+ emin=DECNUMMINE;
+ digits=DECNUMMAXP;
+ if (ae<emin-(digits-1)) {
+ #if DECTRACE || DECVERB
+ printf("Adjusted exponent underflow [%ld].\n", (LI)ae);
+ uprv_decNumberShow(dn);
+ #endif
+ return 1;}
+ if (ae>+emax) {
+ #if DECTRACE || DECVERB
+ printf("Adjusted exponent overflow [%ld].\n", (LI)ae);
+ uprv_decNumberShow(dn);
+ #endif
+ return 1;}
+
+ return 0; /* it's OK */
+ } /* decCheckNumber */
+
+/* ------------------------------------------------------------------ */
+/* decCheckInexact -- check a normal finite inexact result has digits */
+/* dn is the number to check */
+/* set is the context (for status and precision) */
+/* sets Invalid operation, etc., if some digits are missing */
+/* [this check is not made for DECSUBSET compilation or when */
+/* subnormal is not set] */
+/* ------------------------------------------------------------------ */
+static void decCheckInexact(const decNumber *dn, decContext *set) {
+ #if !DECSUBSET && DECEXTFLAG
+ if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact
+ && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) {
+ #if DECTRACE || DECVERB
+ printf("Insufficient digits [%ld] on normal Inexact result.\n",
+ (LI)dn->digits);
+ uprv_decNumberShow(dn);
+ #endif
+ uprv_decContextSetStatus(set, DEC_Invalid_operation);
+ }
+ #else
+ /* next is a noop for quiet compiler */
+ if (dn!=NULL && dn->digits==0) set->status|=DEC_Invalid_operation;
+ #endif
+ return;
+ } /* decCheckInexact */
+#endif
+
+#if DECALLOC
+#undef malloc
+#undef free
+/* ------------------------------------------------------------------ */
+/* decMalloc -- accountable allocation routine */
+/* n is the number of bytes to allocate */
+/* */
+/* Semantics is the same as the stdlib malloc routine, but bytes */
+/* allocated are accounted for globally, and corruption fences are */
+/* added before and after the 'actual' storage. */
+/* ------------------------------------------------------------------ */
+/* This routine allocates storage with an extra twelve bytes; 8 are */
+/* at the start and hold: */
+/* 0-3 the original length requested */
+/* 4-7 buffer corruption detection fence (DECFENCE, x4) */
+/* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */
+/* ------------------------------------------------------------------ */
+static void *decMalloc(size_t n) {
+ uInt size=n+12; /* true size */
+ void *alloc; /* -> allocated storage */
+ uByte *b, *b0; /* work */
+ uInt uiwork; /* for macros */
+
+ alloc=malloc(size); /* -> allocated storage */
+ if (alloc==NULL) return NULL; /* out of strorage */
+ b0=(uByte *)alloc; /* as bytes */
+ decAllocBytes+=n; /* account for storage */
+ UBFROMUI(alloc, n); /* save n */
+ /* printf(" alloc ++ dAB: %ld (%ld)\n", (LI)decAllocBytes, (LI)n); */
+ for (b=b0+4; b<b0+8; b++) *b=DECFENCE;
+ for (b=b0+n+8; b<b0+n+12; b++) *b=DECFENCE;
+ return b0+8; /* -> play area */
+ } /* decMalloc */
+
+/* ------------------------------------------------------------------ */
+/* decFree -- accountable free routine */
+/* alloc is the storage to free */
+/* */
+/* Semantics is the same as the stdlib malloc routine, except that */
+/* the global storage accounting is updated and the fences are */
+/* checked to ensure that no routine has written 'out of bounds'. */
+/* ------------------------------------------------------------------ */
+/* This routine first checks that the fences have not been corrupted. */
+/* It then frees the storage using the 'truw' storage address (that */
+/* is, offset by 8). */
+/* ------------------------------------------------------------------ */
+static void decFree(void *alloc) {
+ uInt n; /* original length */
+ uByte *b, *b0; /* work */
+ uInt uiwork; /* for macros */
+
+ if (alloc==NULL) return; /* allowed; it's a nop */
+ b0=(uByte *)alloc; /* as bytes */
+ b0-=8; /* -> true start of storage */
+ n=UBTOUI(b0); /* lift length */
+ for (b=b0+4; b<b0+8; b++) if (*b!=DECFENCE)
+ printf("=== Corrupt byte [%02x] at offset %d from %ld ===\n", *b,
+ b-b0-8, (LI)b0);
+ for (b=b0+n+8; b<b0+n+12; b++) if (*b!=DECFENCE)
+ printf("=== Corrupt byte [%02x] at offset +%d from %ld, n=%ld ===\n", *b,
+ b-b0-8, (LI)b0, (LI)n);
+ free(b0); /* drop the storage */
+ decAllocBytes-=n; /* account for storage */
+ /* printf(" free -- dAB: %d (%d)\n", decAllocBytes, -n); */
+ } /* decFree */
+#define malloc(a) decMalloc(a)
+#define free(a) decFree(a)
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decNumber.h b/Build/source/libs/icu/icu-4.8.1/i18n/decNumber.h
new file mode 100644
index 00000000000..4fe06497754
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decNumber.h
@@ -0,0 +1,196 @@
+/* ------------------------------------------------------------------ */
+/* Decimal Number arithmetic module header */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2010. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+
+/* Modified version, for use from within ICU.
+ * Renamed public functions, to avoid an unwanted export of the
+ * standard names from the ICU library.
+ *
+ * Use ICU's uprv_malloc() and uprv_free()
+ *
+ * Revert comment syntax to plain C
+ *
+ * Remove a few compiler warnings.
+ */
+
+#if !defined(DECNUMBER)
+ #define DECNUMBER
+ #define DECNAME "decNumber" /* Short name */
+ #define DECFULLNAME "Decimal Number Module" /* Verbose name */
+ #define DECAUTHOR "Mike Cowlishaw" /* Who to blame */
+
+ #if !defined(DECCONTEXT)
+ #include "decContext.h"
+ #endif
+
+ /* Bit settings for decNumber.bits */
+ #define DECNEG 0x80 /* Sign; 1=negative, 0=positive or zero */
+ #define DECINF 0x40 /* 1=Infinity */
+ #define DECNAN 0x20 /* 1=NaN */
+ #define DECSNAN 0x10 /* 1=sNaN */
+ /* The remaining bits are reserved; they must be 0 */
+ #define DECSPECIAL (DECINF|DECNAN|DECSNAN) /* any special value */
+
+ /* Define the decNumber data structure. The size and shape of the */
+ /* units array in the structure is determined by the following */
+ /* constant. This must not be changed without recompiling the */
+ /* decNumber library modules. */
+
+ /* For ICU, use one digit per byte, to make it easier to emulate the
+ * old DigitList interface on top of a decNumber
+ */
+ #define DECDPUN 1 /* DECimal Digits Per UNit [must be >0 */
+ /* and <10; 3 or powers of 2 are best]. */
+
+ /* DECNUMDIGITS is the default number of digits that can be held in */
+ /* the structure. If undefined, 1 is assumed and it is assumed */
+ /* that the structure will be immediately followed by extra space, */
+ /* as required. DECNUMDIGITS is always >0. */
+ #if !defined(DECNUMDIGITS)
+ #define DECNUMDIGITS 1
+ #endif
+
+ /* The size (integer data type) of each unit is determined by the */
+ /* number of digits it will hold. */
+ #if DECDPUN<=2
+ #define decNumberUnit uint8_t
+ #elif DECDPUN<=4
+ #define decNumberUnit uint16_t
+ #else
+ #define decNumberUnit uint32_t
+ #endif
+ /* The number of units needed is ceil(DECNUMDIGITS/DECDPUN) */
+ #define DECNUMUNITS ((DECNUMDIGITS+DECDPUN-1)/DECDPUN)
+
+ /* The data structure... */
+ typedef struct {
+ int32_t digits; /* Count of digits in the coefficient; >0 */
+ int32_t exponent; /* Unadjusted exponent, unbiased, in */
+ /* range: -1999999997 through 999999999 */
+ uint8_t bits; /* Indicator bits (see above) */
+ /* Coefficient, from least significant unit */
+ decNumberUnit lsu[DECNUMUNITS];
+ } decNumber;
+
+ /* Notes: */
+ /* 1. If digits is > DECDPUN then there will one or more */
+ /* decNumberUnits immediately following the first element of lsu.*/
+ /* These contain the remaining (more significant) digits of the */
+ /* number, and may be in the lsu array, or may be guaranteed by */
+ /* some other mechanism (such as being contained in another */
+ /* structure, or being overlaid on dynamically allocated */
+ /* storage). */
+ /* */
+ /* Each integer of the coefficient (except potentially the last) */
+ /* contains DECDPUN digits (e.g., a value in the range 0 through */
+ /* 99999999 if DECDPUN is 8, or 0 through 999 if DECDPUN is 3). */
+ /* */
+ /* 2. A decNumber converted to a string may need up to digits+14 */
+ /* characters. The worst cases (non-exponential and exponential */
+ /* formats) are -0.00000{9...}# and -9.{9...}E+999999999# */
+ /* (where # is '\0') */
+
+
+ /* ---------------------------------------------------------------- */
+ /* decNumber public functions and macros */
+ /* ---------------------------------------------------------------- */
+ /* Conversions */
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *, int32_t);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *, uint32_t);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *, const char *, decContext *);
+ U_INTERNAL char * U_EXPORT2 uprv_decNumberToString(const decNumber *, char *);
+ U_INTERNAL char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *, char *);
+ U_INTERNAL uint32_t U_EXPORT2 uprv_decNumberToUInt32(const decNumber *, decContext *);
+ U_INTERNAL int32_t U_EXPORT2 uprv_decNumberToInt32(const decNumber *, decContext *);
+ U_INTERNAL uint8_t * U_EXPORT2 uprv_decNumberGetBCD(const decNumber *, uint8_t *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSetBCD(decNumber *, const uint8_t *, uint32_t);
+
+ /* Operators and elementary functions */
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *, const decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberLn(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberLogB(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberLog10(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMaxMag(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMinMag(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMinus(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNormalize(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberOr(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberPlus(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberReduce(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRotate(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberScaleB(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberShift(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSquareRoot(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberToIntegralExact(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberToIntegralValue(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberXor(decNumber *, const decNumber *, const decNumber *, decContext *);
+
+ /* Utilities */
+ enum decClass uprv_decNumberClass(const decNumber *, decContext *);
+ U_INTERNAL const char * U_EXPORT2 uprv_decNumberClassToString(enum decClass);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopy(decNumber *, const decNumber *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopyAbs(decNumber *, const decNumber *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopyNegate(decNumber *, const decNumber *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopySign(decNumber *, const decNumber *, const decNumber *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNextMinus(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNextPlus(decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNextToward(decNumber *, const decNumber *, const decNumber *, decContext *);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberTrim(decNumber *);
+ U_INTERNAL const char * U_EXPORT2 uprv_decNumberVersion(void);
+ U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberZero(decNumber *);
+
+ /* Functions for testing decNumbers (normality depends on context) */
+ U_INTERNAL int32_t U_EXPORT2 uprv_decNumberIsNormal(const decNumber *, decContext *);
+ U_INTERNAL int32_t U_EXPORT2 uprv_decNumberIsSubnormal(const decNumber *, decContext *);
+
+ /* Macros for testing decNumber *dn */
+ #define decNumberIsCanonical(dn) (1) /* All decNumbers are saintly */
+ #define decNumberIsFinite(dn) (((dn)->bits&DECSPECIAL)==0)
+ #define decNumberIsInfinite(dn) (((dn)->bits&DECINF)!=0)
+ #define decNumberIsNaN(dn) (((dn)->bits&(DECNAN|DECSNAN))!=0)
+ #define decNumberIsNegative(dn) (((dn)->bits&DECNEG)!=0)
+ #define decNumberIsQNaN(dn) (((dn)->bits&(DECNAN))!=0)
+ #define decNumberIsSNaN(dn) (((dn)->bits&(DECSNAN))!=0)
+ #define decNumberIsSpecial(dn) (((dn)->bits&DECSPECIAL)!=0)
+ #define decNumberIsZero(dn) (*(dn)->lsu==0 \
+ && (dn)->digits==1 \
+ && (((dn)->bits&DECSPECIAL)==0))
+ #define decNumberRadix(dn) (10)
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decNumberLocal.h b/Build/source/libs/icu/icu-4.8.1/i18n/decNumberLocal.h
new file mode 100644
index 00000000000..4a36723ea7e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decNumberLocal.h
@@ -0,0 +1,735 @@
+/* ------------------------------------------------------------------ */
+/* decNumber package local type, tuning, and macro definitions */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2010. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+/* This header file is included by all modules in the decNumber */
+/* library, and contains local type definitions, tuning parameters, */
+/* etc. It should not need to be used by application programs. */
+/* decNumber.h or one of decDouble (etc.) must be included first. */
+/* ------------------------------------------------------------------ */
+
+#if !defined(DECNUMBERLOC)
+ #define DECNUMBERLOC
+ #define DECVERSION "decNumber 3.61" /* Package Version [16 max.] */
+ #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */
+
+ #include <stdlib.h> /* for abs */
+ #include <string.h> /* for memset, strcpy */
+
+ /* Conditional code flag -- set this to match hardware platform */
+ #if !defined(DECLITEND)
+ #define DECLITEND 1 /* 1=little-endian, 0=big-endian */
+ #endif
+
+ /* Conditional code flag -- set this to 1 for best performance */
+ #if !defined(DECUSE64)
+ #define DECUSE64 1 /* 1=use int64s, 0=int32 & smaller only */
+ #endif
+
+ /* Conditional check flags -- set these to 0 for best performance */
+ #if !defined(DECCHECK)
+ #define DECCHECK 0 /* 1 to enable robust checking */
+ #endif
+ #if !defined(DECALLOC)
+ #define DECALLOC 0 /* 1 to enable memory accounting */
+ #endif
+ #if !defined(DECTRACE)
+ #define DECTRACE 0 /* 1 to trace certain internals, etc. */
+ #endif
+
+ /* Tuning parameter for decNumber (arbitrary precision) module */
+ #if !defined(DECBUFFER)
+ #define DECBUFFER 36 /* Size basis for local buffers. This */
+ /* should be a common maximum precision */
+ /* rounded up to a multiple of 4; must */
+ /* be zero or positive. */
+ #endif
+
+ /* ---------------------------------------------------------------- */
+ /* Definitions for all modules (general-purpose) */
+ /* ---------------------------------------------------------------- */
+
+ /* Local names for common types -- for safety, decNumber modules do */
+ /* not use int or long directly. */
+ #define Flag uint8_t
+ #define Byte int8_t
+ #define uByte uint8_t
+ #define Short int16_t
+ #define uShort uint16_t
+ #define Int int32_t
+ #define uInt uint32_t
+ #define Unit decNumberUnit
+ #if DECUSE64
+ #define Long int64_t
+ #define uLong uint64_t
+ #endif
+
+ /* Development-use definitions */
+ typedef long int LI; /* for printf arguments only */
+ #define DECNOINT 0 /* 1 to check no internal use of 'int' */
+ /* or stdint types */
+ #if DECNOINT
+ /* if these interfere with your C includes, do not set DECNOINT */
+ #define int ? /* enable to ensure that plain C 'int' */
+ #define long ?? /* .. or 'long' types are not used */
+ #endif
+
+ /* Shared lookup tables */
+ extern const uByte DECSTICKYTAB[10]; /* re-round digits if sticky */
+ extern const uInt DECPOWERS[10]; /* powers of ten table */
+ /* The following are included from decDPD.h */
+ extern const uShort DPD2BIN[1024]; /* DPD -> 0-999 */
+ extern const uShort BIN2DPD[1000]; /* 0-999 -> DPD */
+ extern const uInt DPD2BINK[1024]; /* DPD -> 0-999000 */
+ extern const uInt DPD2BINM[1024]; /* DPD -> 0-999000000 */
+ extern const uByte DPD2BCD8[4096]; /* DPD -> ddd + len */
+ extern const uByte BIN2BCD8[4000]; /* 0-999 -> ddd + len */
+ extern const uShort BCD2DPD[2458]; /* 0-0x999 -> DPD (0x999=2457)*/
+
+ /* LONGMUL32HI -- set w=(u*v)>>32, where w, u, and v are uInts */
+ /* (that is, sets w to be the high-order word of the 64-bit result; */
+ /* the low-order word is simply u*v.) */
+ /* This version is derived from Knuth via Hacker's Delight; */
+ /* it seems to optimize better than some others tried */
+ #define LONGMUL32HI(w, u, v) { \
+ uInt u0, u1, v0, v1, w0, w1, w2, t; \
+ u0=u & 0xffff; u1=u>>16; \
+ v0=v & 0xffff; v1=v>>16; \
+ w0=u0*v0; \
+ t=u1*v0 + (w0>>16); \
+ w1=t & 0xffff; w2=t>>16; \
+ w1=u0*v1 + w1; \
+ (w)=u1*v1 + w2 + (w1>>16);}
+
+ /* ROUNDUP -- round an integer up to a multiple of n */
+ #define ROUNDUP(i, n) ((((i)+(n)-1)/n)*n)
+ #define ROUNDUP4(i) (((i)+3)&~3) /* special for n=4 */
+
+ /* ROUNDDOWN -- round an integer down to a multiple of n */
+ #define ROUNDDOWN(i, n) (((i)/n)*n)
+ #define ROUNDDOWN4(i) ((i)&~3) /* special for n=4 */
+
+ /* References to multi-byte sequences under different sizes; these */
+ /* require locally declared variables, but do not violate strict */
+ /* aliasing or alignment (as did the UINTAT simple cast to uInt). */
+ /* Variables needed are uswork, uiwork, etc. [so do not use at same */
+ /* level in an expression, e.g., UBTOUI(x)==UBTOUI(y) may fail]. */
+
+ /* Return a uInt, etc., from bytes starting at a char* or uByte* */
+ #define UBTOUS(b) (memcpy((void *)&uswork, b, 2), uswork)
+ #define UBTOUI(b) (memcpy((void *)&uiwork, b, 4), uiwork)
+
+ /* Store a uInt, etc., into bytes starting at a char* or uByte*. */
+ /* Returns i, evaluated, for convenience; has to use uiwork because */
+ /* i may be an expression. */
+ #define UBFROMUS(b, i) (uswork=(i), memcpy(b, (void *)&uswork, 2), uswork)
+ #define UBFROMUI(b, i) (uiwork=(i), memcpy(b, (void *)&uiwork, 4), uiwork)
+
+ /* X10 and X100 -- multiply integer i by 10 or 100 */
+ /* [shifts are usually faster than multiply; could be conditional] */
+ #define X10(i) (((i)<<1)+((i)<<3))
+ #define X100(i) (((i)<<2)+((i)<<5)+((i)<<6))
+
+ /* MAXI and MINI -- general max & min (not in ANSI) for integers */
+ #define MAXI(x,y) ((x)<(y)?(y):(x))
+ #define MINI(x,y) ((x)>(y)?(y):(x))
+
+ /* Useful constants */
+ #define BILLION 1000000000 /* 10**9 */
+ /* CHARMASK: 0x30303030 for ASCII/UTF8; 0xF0F0F0F0 for EBCDIC */
+ #define CHARMASK ((((((((uInt)'0')<<8)+'0')<<8)+'0')<<8)+'0')
+
+
+ /* ---------------------------------------------------------------- */
+ /* Definitions for arbitary-precision modules (only valid after */
+ /* decNumber.h has been included) */
+ /* ---------------------------------------------------------------- */
+
+ /* Limits and constants */
+ #define DECNUMMAXP 999999999 /* maximum precision code can handle */
+ #define DECNUMMAXE 999999999 /* maximum adjusted exponent ditto */
+ #define DECNUMMINE -999999999 /* minimum adjusted exponent ditto */
+ #if (DECNUMMAXP != DEC_MAX_DIGITS)
+ #error Maximum digits mismatch
+ #endif
+ #if (DECNUMMAXE != DEC_MAX_EMAX)
+ #error Maximum exponent mismatch
+ #endif
+ #if (DECNUMMINE != DEC_MIN_EMIN)
+ #error Minimum exponent mismatch
+ #endif
+
+ /* Set DECDPUNMAX -- the maximum integer that fits in DECDPUN */
+ /* digits, and D2UTABLE -- the initializer for the D2U table */
+ #if DECDPUN==1
+ #define DECDPUNMAX 9
+ #define D2UTABLE {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, \
+ 18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, \
+ 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, \
+ 48,49}
+ #elif DECDPUN==2
+ #define DECDPUNMAX 99
+ #define D2UTABLE {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10, \
+ 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18, \
+ 18,19,19,20,20,21,21,22,22,23,23,24,24,25}
+ #elif DECDPUN==3
+ #define DECDPUNMAX 999
+ #define D2UTABLE {0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7, \
+ 8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13, \
+ 13,14,14,14,15,15,15,16,16,16,17}
+ #elif DECDPUN==4
+ #define DECDPUNMAX 9999
+ #define D2UTABLE {0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6, \
+ 6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11, \
+ 11,11,11,12,12,12,12,13}
+ #elif DECDPUN==5
+ #define DECDPUNMAX 99999
+ #define D2UTABLE {0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5, \
+ 5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9, \
+ 9,9,10,10,10,10}
+ #elif DECDPUN==6
+ #define DECDPUNMAX 999999
+ #define D2UTABLE {0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4, \
+ 4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8, \
+ 8,8,8,8,8,9}
+ #elif DECDPUN==7
+ #define DECDPUNMAX 9999999
+ #define D2UTABLE {0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3, \
+ 4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7, \
+ 7,7,7,7,7,7}
+ #elif DECDPUN==8
+ #define DECDPUNMAX 99999999
+ #define D2UTABLE {0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3, \
+ 3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6, \
+ 6,6,6,6,6,7}
+ #elif DECDPUN==9
+ #define DECDPUNMAX 999999999
+ #define D2UTABLE {0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3, \
+ 3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5, \
+ 5,5,6,6,6,6}
+ #elif defined(DECDPUN)
+ #error DECDPUN must be in the range 1-9
+ #endif
+
+ /* ----- Shared data (in decNumber.c) ----- */
+ /* Public lookup table used by the D2U macro (see below) */
+ #define DECMAXD2U 49
+ extern const uByte d2utable[DECMAXD2U+1];
+
+ /* ----- Macros ----- */
+ /* ISZERO -- return true if decNumber dn is a zero */
+ /* [performance-critical in some situations] */
+ #define ISZERO(dn) decNumberIsZero(dn) /* now just a local name */
+
+ /* D2U -- return the number of Units needed to hold d digits */
+ /* (runtime version, with table lookaside for small d) */
+ #if DECDPUN==8
+ #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+7)>>3))
+ #elif DECDPUN==4
+ #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+3)>>2))
+ #else
+ #define D2U(d) ((d)<=DECMAXD2U?d2utable[d]:((d)+DECDPUN-1)/DECDPUN)
+ #endif
+ /* SD2U -- static D2U macro (for compile-time calculation) */
+ #define SD2U(d) (((d)+DECDPUN-1)/DECDPUN)
+
+ /* MSUDIGITS -- returns digits in msu, from digits, calculated */
+ /* using D2U */
+ #define MSUDIGITS(d) ((d)-(D2U(d)-1)*DECDPUN)
+
+ /* D2N -- return the number of decNumber structs that would be */
+ /* needed to contain that number of digits (and the initial */
+ /* decNumber struct) safely. Note that one Unit is included in the */
+ /* initial structure. Used for allocating space that is aligned on */
+ /* a decNumber struct boundary. */
+ #define D2N(d) \
+ ((((SD2U(d)-1)*sizeof(Unit))+sizeof(decNumber)*2-1)/sizeof(decNumber))
+
+ /* TODIGIT -- macro to remove the leading digit from the unsigned */
+ /* integer u at column cut (counting from the right, LSD=0) and */
+ /* place it as an ASCII character into the character pointed to by */
+ /* c. Note that cut must be <= 9, and the maximum value for u is */
+ /* 2,000,000,000 (as is needed for negative exponents of */
+ /* subnormals). The unsigned integer pow is used as a temporary */
+ /* variable. */
+ #define TODIGIT(u, cut, c, pow) { \
+ *(c)='0'; \
+ pow=DECPOWERS[cut]*2; \
+ if ((u)>pow) { \
+ pow*=4; \
+ if ((u)>=pow) {(u)-=pow; *(c)+=8;} \
+ pow/=2; \
+ if ((u)>=pow) {(u)-=pow; *(c)+=4;} \
+ pow/=2; \
+ } \
+ if ((u)>=pow) {(u)-=pow; *(c)+=2;} \
+ pow/=2; \
+ if ((u)>=pow) {(u)-=pow; *(c)+=1;} \
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Definitions for fixed-precision modules (only valid after */
+ /* decSingle.h, decDouble.h, or decQuad.h has been included) */
+ /* ---------------------------------------------------------------- */
+
+ /* bcdnum -- a structure describing a format-independent finite */
+ /* number, whose coefficient is a string of bcd8 uBytes */
+ typedef struct {
+ uByte *msd; /* -> most significant digit */
+ uByte *lsd; /* -> least ditto */
+ uInt sign; /* 0=positive, DECFLOAT_Sign=negative */
+ Int exponent; /* Unadjusted signed exponent (q), or */
+ /* DECFLOAT_NaN etc. for a special */
+ } bcdnum;
+
+ /* Test if exponent or bcdnum exponent must be a special, etc. */
+ #define EXPISSPECIAL(exp) ((exp)>=DECFLOAT_MinSp)
+ #define EXPISINF(exp) (exp==DECFLOAT_Inf)
+ #define EXPISNAN(exp) (exp==DECFLOAT_qNaN || exp==DECFLOAT_sNaN)
+ #define NUMISSPECIAL(num) (EXPISSPECIAL((num)->exponent))
+
+ /* Refer to a 32-bit word or byte in a decFloat (df) by big-endian */
+ /* (array) notation (the 0 word or byte contains the sign bit), */
+ /* automatically adjusting for endianness; similarly address a word */
+ /* in the next-wider format (decFloatWider, or dfw) */
+ #define DECWORDS (DECBYTES/4)
+ #define DECWWORDS (DECWBYTES/4)
+ #if DECLITEND
+ #define DFBYTE(df, off) ((df)->bytes[DECBYTES-1-(off)])
+ #define DFWORD(df, off) ((df)->words[DECWORDS-1-(off)])
+ #define DFWWORD(dfw, off) ((dfw)->words[DECWWORDS-1-(off)])
+ #else
+ #define DFBYTE(df, off) ((df)->bytes[off])
+ #define DFWORD(df, off) ((df)->words[off])
+ #define DFWWORD(dfw, off) ((dfw)->words[off])
+ #endif
+
+ /* Tests for sign or specials, directly on DECFLOATs */
+ #define DFISSIGNED(df) (DFWORD(df, 0)&0x80000000)
+ #define DFISSPECIAL(df) ((DFWORD(df, 0)&0x78000000)==0x78000000)
+ #define DFISINF(df) ((DFWORD(df, 0)&0x7c000000)==0x78000000)
+ #define DFISNAN(df) ((DFWORD(df, 0)&0x7c000000)==0x7c000000)
+ #define DFISQNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7c000000)
+ #define DFISSNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7e000000)
+
+ /* Shared lookup tables */
+ extern const uInt DECCOMBMSD[64]; /* Combination field -> MSD */
+ extern const uInt DECCOMBFROM[48]; /* exp+msd -> Combination */
+
+ /* Private generic (utility) routine */
+ #if DECCHECK || DECTRACE
+ extern void decShowNum(const bcdnum *, const char *);
+ #endif
+
+ /* Format-dependent macros and constants */
+ #if defined(DECPMAX)
+
+ /* Useful constants */
+ #define DECPMAX9 (ROUNDUP(DECPMAX, 9)/9) /* 'Pmax' in 10**9s */
+ /* Top words for a zero */
+ #define SINGLEZERO 0x22500000
+ #define DOUBLEZERO 0x22380000
+ #define QUADZERO 0x22080000
+ /* [ZEROWORD is defined to be one of these in the DFISZERO macro] */
+
+ /* Format-dependent common tests: */
+ /* DFISZERO -- test for (any) zero */
+ /* DFISCCZERO -- test for coefficient continuation being zero */
+ /* DFISCC01 -- test for coefficient contains only 0s and 1s */
+ /* DFISINT -- test for finite and exponent q=0 */
+ /* DFISUINT01 -- test for sign=0, finite, exponent q=0, and */
+ /* MSD=0 or 1 */
+ /* ZEROWORD is also defined here. */
+ /* In DFISZERO the first test checks the least-significant word */
+ /* (most likely to be non-zero); the penultimate tests MSD and */
+ /* DPDs in the signword, and the final test excludes specials and */
+ /* MSD>7. DFISINT similarly has to allow for the two forms of */
+ /* MSD codes. DFISUINT01 only has to allow for one form of MSD */
+ /* code. */
+ #if DECPMAX==7
+ #define ZEROWORD SINGLEZERO
+ /* [test macros not needed except for Zero] */
+ #define DFISZERO(df) ((DFWORD(df, 0)&0x1c0fffff)==0 \
+ && (DFWORD(df, 0)&0x60000000)!=0x60000000)
+ #elif DECPMAX==16
+ #define ZEROWORD DOUBLEZERO
+ #define DFISZERO(df) ((DFWORD(df, 1)==0 \
+ && (DFWORD(df, 0)&0x1c03ffff)==0 \
+ && (DFWORD(df, 0)&0x60000000)!=0x60000000))
+ #define DFISINT(df) ((DFWORD(df, 0)&0x63fc0000)==0x22380000 \
+ ||(DFWORD(df, 0)&0x7bfc0000)==0x6a380000)
+ #define DFISUINT01(df) ((DFWORD(df, 0)&0xfbfc0000)==0x22380000)
+ #define DFISCCZERO(df) (DFWORD(df, 1)==0 \
+ && (DFWORD(df, 0)&0x0003ffff)==0)
+ #define DFISCC01(df) ((DFWORD(df, 0)&~0xfffc9124)==0 \
+ && (DFWORD(df, 1)&~0x49124491)==0)
+ #elif DECPMAX==34
+ #define ZEROWORD QUADZERO
+ #define DFISZERO(df) ((DFWORD(df, 3)==0 \
+ && DFWORD(df, 2)==0 \
+ && DFWORD(df, 1)==0 \
+ && (DFWORD(df, 0)&0x1c003fff)==0 \
+ && (DFWORD(df, 0)&0x60000000)!=0x60000000))
+ #define DFISINT(df) ((DFWORD(df, 0)&0x63ffc000)==0x22080000 \
+ ||(DFWORD(df, 0)&0x7bffc000)==0x6a080000)
+ #define DFISUINT01(df) ((DFWORD(df, 0)&0xfbffc000)==0x22080000)
+ #define DFISCCZERO(df) (DFWORD(df, 3)==0 \
+ && DFWORD(df, 2)==0 \
+ && DFWORD(df, 1)==0 \
+ && (DFWORD(df, 0)&0x00003fff)==0)
+
+ #define DFISCC01(df) ((DFWORD(df, 0)&~0xffffc912)==0 \
+ && (DFWORD(df, 1)&~0x44912449)==0 \
+ && (DFWORD(df, 2)&~0x12449124)==0 \
+ && (DFWORD(df, 3)&~0x49124491)==0)
+ #endif
+
+ /* Macros to test if a certain 10 bits of a uInt or pair of uInts */
+ /* are a canonical declet [higher or lower bits are ignored]. */
+ /* declet is at offset 0 (from the right) in a uInt: */
+ #define CANONDPD(dpd) (((dpd)&0x300)==0 || ((dpd)&0x6e)!=0x6e)
+ /* declet is at offset k (a multiple of 2) in a uInt: */
+ #define CANONDPDOFF(dpd, k) (((dpd)&(0x300<<(k)))==0 \
+ || ((dpd)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k)))
+ /* declet is at offset k (a multiple of 2) in a pair of uInts: */
+ /* [the top 2 bits will always be in the more-significant uInt] */
+ #define CANONDPDTWO(hi, lo, k) (((hi)&(0x300>>(32-(k))))==0 \
+ || ((hi)&(0x6e>>(32-(k))))!=(0x6e>>(32-(k))) \
+ || ((lo)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k)))
+
+ /* Macro to test whether a full-length (length DECPMAX) BCD8 */
+ /* coefficient, starting at uByte u, is all zeros */
+ /* Test just the LSWord first, then the remainder as a sequence */
+ /* of tests in order to avoid same-level use of UBTOUI */
+ #if DECPMAX==7
+ #define ISCOEFFZERO(u) ( \
+ UBTOUI((u)+DECPMAX-4)==0 \
+ && UBTOUS((u)+DECPMAX-6)==0 \
+ && *(u)==0)
+ #elif DECPMAX==16
+ #define ISCOEFFZERO(u) ( \
+ UBTOUI((u)+DECPMAX-4)==0 \
+ && UBTOUI((u)+DECPMAX-8)==0 \
+ && UBTOUI((u)+DECPMAX-12)==0 \
+ && UBTOUI(u)==0)
+ #elif DECPMAX==34
+ #define ISCOEFFZERO(u) ( \
+ UBTOUI((u)+DECPMAX-4)==0 \
+ && UBTOUI((u)+DECPMAX-8)==0 \
+ && UBTOUI((u)+DECPMAX-12)==0 \
+ && UBTOUI((u)+DECPMAX-16)==0 \
+ && UBTOUI((u)+DECPMAX-20)==0 \
+ && UBTOUI((u)+DECPMAX-24)==0 \
+ && UBTOUI((u)+DECPMAX-28)==0 \
+ && UBTOUI((u)+DECPMAX-32)==0 \
+ && UBTOUS(u)==0)
+ #endif
+
+ /* Macros and masks for the exponent continuation field and MSD */
+ /* Get the exponent continuation from a decFloat *df as an Int */
+ #define GETECON(df) ((Int)((DFWORD((df), 0)&0x03ffffff)>>(32-6-DECECONL)))
+ /* Ditto, from the next-wider format */
+ #define GETWECON(df) ((Int)((DFWWORD((df), 0)&0x03ffffff)>>(32-6-DECWECONL)))
+ /* Get the biased exponent similarly */
+ #define GETEXP(df) ((Int)(DECCOMBEXP[DFWORD((df), 0)>>26]+GETECON(df)))
+ /* Get the unbiased exponent similarly */
+ #define GETEXPUN(df) ((Int)GETEXP(df)-DECBIAS)
+ /* Get the MSD similarly (as uInt) */
+ #define GETMSD(df) (DECCOMBMSD[DFWORD((df), 0)>>26])
+
+ /* Compile-time computes of the exponent continuation field masks */
+ /* full exponent continuation field: */
+ #define ECONMASK ((0x03ffffff>>(32-6-DECECONL))<<(32-6-DECECONL))
+ /* same, not including its first digit (the qNaN/sNaN selector): */
+ #define ECONNANMASK ((0x01ffffff>>(32-6-DECECONL))<<(32-6-DECECONL))
+
+ /* Macros to decode the coefficient in a finite decFloat *df into */
+ /* a BCD string (uByte *bcdin) of length DECPMAX uBytes. */
+
+ /* In-line sequence to convert least significant 10 bits of uInt */
+ /* dpd to three BCD8 digits starting at uByte u. Note that an */
+ /* extra byte is written to the right of the three digits because */
+ /* four bytes are moved at a time for speed; the alternative */
+ /* macro moves exactly three bytes (usually slower). */
+ #define dpd2bcd8(u, dpd) memcpy(u, &DPD2BCD8[((dpd)&0x3ff)*4], 4)
+ #define dpd2bcd83(u, dpd) memcpy(u, &DPD2BCD8[((dpd)&0x3ff)*4], 3)
+
+ /* Decode the declets. After extracting each one, it is decoded */
+ /* to BCD8 using a table lookup (also used for variable-length */
+ /* decode). Each DPD decode is 3 bytes BCD8 plus a one-byte */
+ /* length which is not used, here). Fixed-length 4-byte moves */
+ /* are fast, however, almost everywhere, and so are used except */
+ /* for the final three bytes (to avoid overrun). The code below */
+ /* is 36 instructions for Doubles and about 70 for Quads, even */
+ /* on IA32. */
+
+ /* Two macros are defined for each format: */
+ /* GETCOEFF extracts the coefficient of the current format */
+ /* GETWCOEFF extracts the coefficient of the next-wider format. */
+ /* The latter is a copy of the next-wider GETCOEFF using DFWWORD. */
+
+ #if DECPMAX==7
+ #define GETCOEFF(df, bcd) { \
+ uInt sourhi=DFWORD(df, 0); \
+ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
+ dpd2bcd8(bcd+1, sourhi>>10); \
+ dpd2bcd83(bcd+4, sourhi);}
+ #define GETWCOEFF(df, bcd) { \
+ uInt sourhi=DFWWORD(df, 0); \
+ uInt sourlo=DFWWORD(df, 1); \
+ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
+ dpd2bcd8(bcd+1, sourhi>>8); \
+ dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \
+ dpd2bcd8(bcd+7, sourlo>>20); \
+ dpd2bcd8(bcd+10, sourlo>>10); \
+ dpd2bcd83(bcd+13, sourlo);}
+
+ #elif DECPMAX==16
+ #define GETCOEFF(df, bcd) { \
+ uInt sourhi=DFWORD(df, 0); \
+ uInt sourlo=DFWORD(df, 1); \
+ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
+ dpd2bcd8(bcd+1, sourhi>>8); \
+ dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \
+ dpd2bcd8(bcd+7, sourlo>>20); \
+ dpd2bcd8(bcd+10, sourlo>>10); \
+ dpd2bcd83(bcd+13, sourlo);}
+ #define GETWCOEFF(df, bcd) { \
+ uInt sourhi=DFWWORD(df, 0); \
+ uInt sourmh=DFWWORD(df, 1); \
+ uInt sourml=DFWWORD(df, 2); \
+ uInt sourlo=DFWWORD(df, 3); \
+ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
+ dpd2bcd8(bcd+1, sourhi>>4); \
+ dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \
+ dpd2bcd8(bcd+7, sourmh>>16); \
+ dpd2bcd8(bcd+10, sourmh>>6); \
+ dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \
+ dpd2bcd8(bcd+16, sourml>>18); \
+ dpd2bcd8(bcd+19, sourml>>8); \
+ dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \
+ dpd2bcd8(bcd+25, sourlo>>20); \
+ dpd2bcd8(bcd+28, sourlo>>10); \
+ dpd2bcd83(bcd+31, sourlo);}
+
+ #elif DECPMAX==34
+ #define GETCOEFF(df, bcd) { \
+ uInt sourhi=DFWORD(df, 0); \
+ uInt sourmh=DFWORD(df, 1); \
+ uInt sourml=DFWORD(df, 2); \
+ uInt sourlo=DFWORD(df, 3); \
+ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
+ dpd2bcd8(bcd+1, sourhi>>4); \
+ dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \
+ dpd2bcd8(bcd+7, sourmh>>16); \
+ dpd2bcd8(bcd+10, sourmh>>6); \
+ dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \
+ dpd2bcd8(bcd+16, sourml>>18); \
+ dpd2bcd8(bcd+19, sourml>>8); \
+ dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \
+ dpd2bcd8(bcd+25, sourlo>>20); \
+ dpd2bcd8(bcd+28, sourlo>>10); \
+ dpd2bcd83(bcd+31, sourlo);}
+
+ #define GETWCOEFF(df, bcd) {??} /* [should never be used] */
+ #endif
+
+ /* Macros to decode the coefficient in a finite decFloat *df into */
+ /* a base-billion uInt array, with the least-significant */
+ /* 0-999999999 'digit' at offset 0. */
+
+ /* Decode the declets. After extracting each one, it is decoded */
+ /* to binary using a table lookup. Three tables are used; one */
+ /* the usual DPD to binary, the other two pre-multiplied by 1000 */
+ /* and 1000000 to avoid multiplication during decode. These */
+ /* tables can also be used for multiplying up the MSD as the DPD */
+ /* code for 0 through 9 is the identity. */
+ #define DPD2BIN0 DPD2BIN /* for prettier code */
+
+ #if DECPMAX==7
+ #define GETCOEFFBILL(df, buf) { \
+ uInt sourhi=DFWORD(df, 0); \
+ (buf)[0]=DPD2BIN0[sourhi&0x3ff] \
+ +DPD2BINK[(sourhi>>10)&0x3ff] \
+ +DPD2BINM[DECCOMBMSD[sourhi>>26]];}
+
+ #elif DECPMAX==16
+ #define GETCOEFFBILL(df, buf) { \
+ uInt sourhi, sourlo; \
+ sourlo=DFWORD(df, 1); \
+ (buf)[0]=DPD2BIN0[sourlo&0x3ff] \
+ +DPD2BINK[(sourlo>>10)&0x3ff] \
+ +DPD2BINM[(sourlo>>20)&0x3ff]; \
+ sourhi=DFWORD(df, 0); \
+ (buf)[1]=DPD2BIN0[((sourhi<<2) | (sourlo>>30))&0x3ff] \
+ +DPD2BINK[(sourhi>>8)&0x3ff] \
+ +DPD2BINM[DECCOMBMSD[sourhi>>26]];}
+
+ #elif DECPMAX==34
+ #define GETCOEFFBILL(df, buf) { \
+ uInt sourhi, sourmh, sourml, sourlo; \
+ sourlo=DFWORD(df, 3); \
+ (buf)[0]=DPD2BIN0[sourlo&0x3ff] \
+ +DPD2BINK[(sourlo>>10)&0x3ff] \
+ +DPD2BINM[(sourlo>>20)&0x3ff]; \
+ sourml=DFWORD(df, 2); \
+ (buf)[1]=DPD2BIN0[((sourml<<2) | (sourlo>>30))&0x3ff] \
+ +DPD2BINK[(sourml>>8)&0x3ff] \
+ +DPD2BINM[(sourml>>18)&0x3ff]; \
+ sourmh=DFWORD(df, 1); \
+ (buf)[2]=DPD2BIN0[((sourmh<<4) | (sourml>>28))&0x3ff] \
+ +DPD2BINK[(sourmh>>6)&0x3ff] \
+ +DPD2BINM[(sourmh>>16)&0x3ff]; \
+ sourhi=DFWORD(df, 0); \
+ (buf)[3]=DPD2BIN0[((sourhi<<6) | (sourmh>>26))&0x3ff] \
+ +DPD2BINK[(sourhi>>4)&0x3ff] \
+ +DPD2BINM[DECCOMBMSD[sourhi>>26]];}
+
+ #endif
+
+ /* Macros to decode the coefficient in a finite decFloat *df into */
+ /* a base-thousand uInt array (of size DECLETS+1, to allow for */
+ /* the MSD), with the least-significant 0-999 'digit' at offset 0.*/
+
+ /* Decode the declets. After extracting each one, it is decoded */
+ /* to binary using a table lookup. */
+ #if DECPMAX==7
+ #define GETCOEFFTHOU(df, buf) { \
+ uInt sourhi=DFWORD(df, 0); \
+ (buf)[0]=DPD2BIN[sourhi&0x3ff]; \
+ (buf)[1]=DPD2BIN[(sourhi>>10)&0x3ff]; \
+ (buf)[2]=DECCOMBMSD[sourhi>>26];}
+
+ #elif DECPMAX==16
+ #define GETCOEFFTHOU(df, buf) { \
+ uInt sourhi, sourlo; \
+ sourlo=DFWORD(df, 1); \
+ (buf)[0]=DPD2BIN[sourlo&0x3ff]; \
+ (buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \
+ (buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \
+ sourhi=DFWORD(df, 0); \
+ (buf)[3]=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \
+ (buf)[4]=DPD2BIN[(sourhi>>8)&0x3ff]; \
+ (buf)[5]=DECCOMBMSD[sourhi>>26];}
+
+ #elif DECPMAX==34
+ #define GETCOEFFTHOU(df, buf) { \
+ uInt sourhi, sourmh, sourml, sourlo; \
+ sourlo=DFWORD(df, 3); \
+ (buf)[0]=DPD2BIN[sourlo&0x3ff]; \
+ (buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \
+ (buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \
+ sourml=DFWORD(df, 2); \
+ (buf)[3]=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \
+ (buf)[4]=DPD2BIN[(sourml>>8)&0x3ff]; \
+ (buf)[5]=DPD2BIN[(sourml>>18)&0x3ff]; \
+ sourmh=DFWORD(df, 1); \
+ (buf)[6]=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \
+ (buf)[7]=DPD2BIN[(sourmh>>6)&0x3ff]; \
+ (buf)[8]=DPD2BIN[(sourmh>>16)&0x3ff]; \
+ sourhi=DFWORD(df, 0); \
+ (buf)[9]=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \
+ (buf)[10]=DPD2BIN[(sourhi>>4)&0x3ff]; \
+ (buf)[11]=DECCOMBMSD[sourhi>>26];}
+ #endif
+
+
+ /* Macros to decode the coefficient in a finite decFloat *df and */
+ /* add to a base-thousand uInt array (as for GETCOEFFTHOU). */
+ /* After the addition then most significant 'digit' in the array */
+ /* might have a value larger then 10 (with a maximum of 19). */
+ #if DECPMAX==7
+ #define ADDCOEFFTHOU(df, buf) { \
+ uInt sourhi=DFWORD(df, 0); \
+ (buf)[0]+=DPD2BIN[sourhi&0x3ff]; \
+ if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \
+ (buf)[1]+=DPD2BIN[(sourhi>>10)&0x3ff]; \
+ if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \
+ (buf)[2]+=DECCOMBMSD[sourhi>>26];}
+
+ #elif DECPMAX==16
+ #define ADDCOEFFTHOU(df, buf) { \
+ uInt sourhi, sourlo; \
+ sourlo=DFWORD(df, 1); \
+ (buf)[0]+=DPD2BIN[sourlo&0x3ff]; \
+ if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \
+ (buf)[1]+=DPD2BIN[(sourlo>>10)&0x3ff]; \
+ if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \
+ (buf)[2]+=DPD2BIN[(sourlo>>20)&0x3ff]; \
+ if (buf[2]>999) {buf[2]-=1000; buf[3]++;} \
+ sourhi=DFWORD(df, 0); \
+ (buf)[3]+=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \
+ if (buf[3]>999) {buf[3]-=1000; buf[4]++;} \
+ (buf)[4]+=DPD2BIN[(sourhi>>8)&0x3ff]; \
+ if (buf[4]>999) {buf[4]-=1000; buf[5]++;} \
+ (buf)[5]+=DECCOMBMSD[sourhi>>26];}
+
+ #elif DECPMAX==34
+ #define ADDCOEFFTHOU(df, buf) { \
+ uInt sourhi, sourmh, sourml, sourlo; \
+ sourlo=DFWORD(df, 3); \
+ (buf)[0]+=DPD2BIN[sourlo&0x3ff]; \
+ if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \
+ (buf)[1]+=DPD2BIN[(sourlo>>10)&0x3ff]; \
+ if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \
+ (buf)[2]+=DPD2BIN[(sourlo>>20)&0x3ff]; \
+ if (buf[2]>999) {buf[2]-=1000; buf[3]++;} \
+ sourml=DFWORD(df, 2); \
+ (buf)[3]+=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \
+ if (buf[3]>999) {buf[3]-=1000; buf[4]++;} \
+ (buf)[4]+=DPD2BIN[(sourml>>8)&0x3ff]; \
+ if (buf[4]>999) {buf[4]-=1000; buf[5]++;} \
+ (buf)[5]+=DPD2BIN[(sourml>>18)&0x3ff]; \
+ if (buf[5]>999) {buf[5]-=1000; buf[6]++;} \
+ sourmh=DFWORD(df, 1); \
+ (buf)[6]+=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \
+ if (buf[6]>999) {buf[6]-=1000; buf[7]++;} \
+ (buf)[7]+=DPD2BIN[(sourmh>>6)&0x3ff]; \
+ if (buf[7]>999) {buf[7]-=1000; buf[8]++;} \
+ (buf)[8]+=DPD2BIN[(sourmh>>16)&0x3ff]; \
+ if (buf[8]>999) {buf[8]-=1000; buf[9]++;} \
+ sourhi=DFWORD(df, 0); \
+ (buf)[9]+=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \
+ if (buf[9]>999) {buf[9]-=1000; buf[10]++;} \
+ (buf)[10]+=DPD2BIN[(sourhi>>4)&0x3ff]; \
+ if (buf[10]>999) {buf[10]-=1000; buf[11]++;} \
+ (buf)[11]+=DECCOMBMSD[sourhi>>26];}
+ #endif
+
+
+ /* Set a decFloat to the maximum positive finite number (Nmax) */
+ #if DECPMAX==7
+ #define DFSETNMAX(df) \
+ {DFWORD(df, 0)=0x77f3fcff;}
+ #elif DECPMAX==16
+ #define DFSETNMAX(df) \
+ {DFWORD(df, 0)=0x77fcff3f; \
+ DFWORD(df, 1)=0xcff3fcff;}
+ #elif DECPMAX==34
+ #define DFSETNMAX(df) \
+ {DFWORD(df, 0)=0x77ffcff3; \
+ DFWORD(df, 1)=0xfcff3fcf; \
+ DFWORD(df, 2)=0xf3fcff3f; \
+ DFWORD(df, 3)=0xcff3fcff;}
+ #endif
+
+ /* [end of format-dependent macros and constants] */
+ #endif
+
+#else
+ #error decNumberLocal included more than once
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.cpp
new file mode 100644
index 00000000000..687188e1a0d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.cpp
@@ -0,0 +1,241 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* This file contains the class DecimalFormatStaticSets
+*
+* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient
+* parsing of decimal and group separators.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "umutex.h"
+
+#include "decfmtst.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.
+//
+//------------------------------------------------------------------------------
+
+static const UChar gDotEquivalentsPattern[] = {
+ // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ]
+ 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
+
+static const UChar gCommaEquivalentsPattern[] = {
+ // [ , \u060C \u066B \u3001 \uFE10 \uFE11 \uFE50 \uFE51 \uFF0C \uFF64 ]
+ 0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000};
+
+static const UChar gOtherGroupingSeparatorsPattern[] = {
+ // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ]
+ 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
+
+static const UChar gDashEquivalentsPattern[] = {
+ // [ \ - HYPHEN F_DASH N_DASH MINUS ]
+ 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000};
+
+static const UChar gStrictDotEquivalentsPattern[] = {
+ // [ . \u2024 \uFE52 \uFF0E \uFF61 ]
+ 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
+
+static const UChar gStrictCommaEquivalentsPattern[] = {
+ // [ , \u066B \uFE10 \uFE50 \uFF0C ]
+ 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000};
+
+static const UChar gStrictOtherGroupingSeparatorsPattern[] = {
+ // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ]
+ 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
+
+static const UChar gStrictDashEquivalentsPattern[] = {
+ // [ \ - MINUS ]
+ 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000};
+
+
+DecimalFormatStaticSets *DecimalFormatStaticSets::gStaticSets = NULL;
+
+DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode *status)
+: fDotEquivalents(NULL),
+ fCommaEquivalents(NULL),
+ fOtherGroupingSeparators(NULL),
+ fDashEquivalents(NULL),
+ fStrictDotEquivalents(NULL),
+ fStrictCommaEquivalents(NULL),
+ fStrictOtherGroupingSeparators(NULL),
+ fStrictDashEquivalents(NULL),
+ fDefaultGroupingSeparators(NULL),
+ fStrictDefaultGroupingSeparators(NULL)
+{
+ fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), *status);
+ fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), *status);
+ fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), *status);
+ fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), *status);
+
+ fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), *status);
+ fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), *status);
+ fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), *status);
+ fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), *status);
+
+
+ fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents);
+ fDefaultGroupingSeparators->addAll(*fCommaEquivalents);
+ fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators);
+
+ fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents);
+ fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents);
+ fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators);
+
+ // Check for null pointers
+ if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL ||
+ fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL ||
+ fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL) {
+ goto ExitConstrDeleteAll;
+ }
+
+ // Freeze all the sets
+ fDotEquivalents->freeze();
+ fCommaEquivalents->freeze();
+ fOtherGroupingSeparators->freeze();
+ fDashEquivalents->freeze();
+ fStrictDotEquivalents->freeze();
+ fStrictCommaEquivalents->freeze();
+ fStrictOtherGroupingSeparators->freeze();
+ fStrictDashEquivalents->freeze();
+ fDefaultGroupingSeparators->freeze();
+ fStrictDefaultGroupingSeparators->freeze();
+
+ return; // If we reached this point, everything is fine so just exit
+
+ExitConstrDeleteAll: // Remove fPropSets and fRuleSets and return error
+ delete fDotEquivalents; fDotEquivalents = NULL;
+ delete fCommaEquivalents; fCommaEquivalents = NULL;
+ delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL;
+ delete fDashEquivalents; fDashEquivalents = NULL;
+ delete fStrictDotEquivalents; fStrictDotEquivalents = NULL;
+ delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL;
+ delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
+ delete fStrictDashEquivalents; fStrictDashEquivalents = NULL;
+ delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL;
+ delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL;
+ delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
+
+ *status = U_MEMORY_ALLOCATION_ERROR;
+}
+
+
+DecimalFormatStaticSets::~DecimalFormatStaticSets() {
+ delete fDotEquivalents; fDotEquivalents = NULL;
+ delete fCommaEquivalents; fCommaEquivalents = NULL;
+ delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL;
+ delete fDashEquivalents; fDashEquivalents = NULL;
+ delete fStrictDotEquivalents; fStrictDotEquivalents = NULL;
+ delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL;
+ delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
+ delete fStrictDashEquivalents; fStrictDashEquivalents = NULL;
+ delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL;
+ delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL;
+ delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// decfmt_cleanup Memory cleanup function, free/delete all
+// cached memory. Called by ICU's u_cleanup() function.
+//
+//------------------------------------------------------------------------------
+UBool
+DecimalFormatStaticSets::cleanup(void)
+{
+ delete DecimalFormatStaticSets::gStaticSets;
+ DecimalFormatStaticSets::gStaticSets = NULL;
+
+ return TRUE;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+decimfmt_cleanup(void)
+{
+ return DecimalFormatStaticSets::cleanup();
+}
+U_CDECL_END
+
+void DecimalFormatStaticSets::initSets(UErrorCode *status)
+{
+ DecimalFormatStaticSets *p;
+
+ UMTX_CHECK(NULL, gStaticSets, p);
+ if (p == NULL) {
+ p = new DecimalFormatStaticSets(status);
+
+ if (p == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ if (U_FAILURE(*status)) {
+ delete p;
+ return;
+ }
+
+ umtx_lock(NULL);
+ if (gStaticSets == NULL) {
+ gStaticSets = p;
+ p = NULL;
+ }
+
+ umtx_unlock(NULL);
+ if (p != NULL) {
+ delete p;
+ }
+
+ ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup);
+ }
+}
+
+UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse, UnicodeSet *fallback)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ initSets(&status);
+
+ if (U_FAILURE(status)) {
+ fallback->set(decimal, decimal);
+ return fallback;
+ }
+
+ if (gStaticSets->fDotEquivalents->contains(decimal)) {
+ return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents;
+ }
+
+ if (gStaticSets->fCommaEquivalents->contains(decimal)) {
+ return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents;
+ }
+
+ // if there is no match, return the character itself
+ fallback->set(decimal, decimal);
+ return fallback;
+}
+
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.h b/Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.h
new file mode 100644
index 00000000000..d2db3f23d4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decfmtst.h
@@ -0,0 +1,59 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* This file contains declarations for the class DecimalFormatStaticSets
+*
+* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient
+* parsing of decimal and group separators.
+********************************************************************************
+*/
+
+#ifndef DECFMTST_H
+#define DECFMTST_H
+
+#include "unicode/utypes.h"
+
+ #if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+class UnicodeSet;
+
+
+class DecimalFormatStaticSets : public UMemory
+{
+public:
+ static DecimalFormatStaticSets *gStaticSets; // Ptr to all lazily initialized constant
+ // shared sets.
+
+ DecimalFormatStaticSets(UErrorCode *status);
+ ~DecimalFormatStaticSets();
+
+ static void initSets(UErrorCode *status);
+ static UBool cleanup();
+
+ static UnicodeSet *getSimilarDecimals(UChar32 decimal, UBool strictParse, UnicodeSet *fallback);
+
+ UnicodeSet *fDotEquivalents;
+ UnicodeSet *fCommaEquivalents;
+ UnicodeSet *fOtherGroupingSeparators;
+ UnicodeSet *fDashEquivalents;
+
+ UnicodeSet *fStrictDotEquivalents;
+ UnicodeSet *fStrictCommaEquivalents;
+ UnicodeSet *fStrictOtherGroupingSeparators;
+ UnicodeSet *fStrictDashEquivalents;
+
+ UnicodeSet *fDefaultGroupingSeparators;
+ UnicodeSet *fStrictDefaultGroupingSeparators;
+
+};
+
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // DECFMTST_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/decimfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/decimfmt.cpp
new file mode 100644
index 00000000000..a9d7d17285c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/decimfmt.cpp
@@ -0,0 +1,4834 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 "fphdlimp.h"
+#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/uniset.h"
+#include "unicode/curramt.h"
+#include "unicode/currpinf.h"
+#include "unicode/plurrule.h"
+#include "uresimp.h"
+#include "ucurrimp.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "patternprops.h"
+#include "digitlst.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "putilimp.h"
+#include <math.h>
+#include "hash.h"
+#include "decfmtst.h"
+
+
+U_NAMESPACE_BEGIN
+
+/* For currency parsing purose,
+ * Need to remember all prefix patterns and suffix patterns of
+ * every currency format pattern,
+ * including the pattern of default currecny style
+ * and plural currency style. And the patterns are set through applyPattern.
+ */
+struct AffixPatternsForCurrency : public UMemory {
+ // negative prefix pattern
+ UnicodeString negPrefixPatternForCurrency;
+ // negative suffix pattern
+ UnicodeString negSuffixPatternForCurrency;
+ // positive prefix pattern
+ UnicodeString posPrefixPatternForCurrency;
+ // positive suffix pattern
+ UnicodeString posSuffixPatternForCurrency;
+ int8_t patternType;
+
+ AffixPatternsForCurrency(const UnicodeString& negPrefix,
+ const UnicodeString& negSuffix,
+ const UnicodeString& posPrefix,
+ const UnicodeString& posSuffix,
+ int8_t type) {
+ negPrefixPatternForCurrency = negPrefix;
+ negSuffixPatternForCurrency = negSuffix;
+ posPrefixPatternForCurrency = posPrefix;
+ posSuffixPatternForCurrency = posSuffix;
+ patternType = type;
+ }
+};
+
+/* affix for currency formatting when the currency sign in the pattern
+ * equals to 3, such as the pattern contains 3 currency sign or
+ * the formatter style is currency plural format style.
+ */
+struct AffixesForCurrency : public UMemory {
+ // negative prefix
+ UnicodeString negPrefixForCurrency;
+ // negative suffix
+ UnicodeString negSuffixForCurrency;
+ // positive prefix
+ UnicodeString posPrefixForCurrency;
+ // positive suffix
+ UnicodeString posSuffixForCurrency;
+
+ int32_t formatWidth;
+
+ AffixesForCurrency(const UnicodeString& negPrefix,
+ const UnicodeString& negSuffix,
+ const UnicodeString& posPrefix,
+ const UnicodeString& posSuffix) {
+ negPrefixForCurrency = negPrefix;
+ negSuffixForCurrency = negSuffix;
+ posPrefixForCurrency = posPrefix;
+ posSuffixForCurrency = posSuffix;
+ }
+};
+
+U_CDECL_BEGIN
+
+/**
+ * @internal ICU 4.2
+ */
+static UBool U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2);
+
+/**
+ * @internal ICU 4.2
+ */
+static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2);
+
+
+static UBool
+U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2) {
+ const AffixesForCurrency* affix_1 =
+ (AffixesForCurrency*)val1.pointer;
+ const AffixesForCurrency* affix_2 =
+ (AffixesForCurrency*)val2.pointer;
+ return affix_1->negPrefixForCurrency == affix_2->negPrefixForCurrency &&
+ affix_1->negSuffixForCurrency == affix_2->negSuffixForCurrency &&
+ affix_1->posPrefixForCurrency == affix_2->posPrefixForCurrency &&
+ affix_1->posSuffixForCurrency == affix_2->posSuffixForCurrency;
+}
+
+
+static UBool
+U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) {
+ const AffixPatternsForCurrency* affix_1 =
+ (AffixPatternsForCurrency*)val1.pointer;
+ const AffixPatternsForCurrency* affix_2 =
+ (AffixPatternsForCurrency*)val2.pointer;
+ return affix_1->negPrefixPatternForCurrency ==
+ affix_2->negPrefixPatternForCurrency &&
+ affix_1->negSuffixPatternForCurrency ==
+ affix_2->negSuffixPatternForCurrency &&
+ affix_1->posPrefixPatternForCurrency ==
+ affix_2->posPrefixPatternForCurrency &&
+ affix_1->posSuffixPatternForCurrency ==
+ affix_2->posSuffixPatternForCurrency &&
+ affix_1->patternType == affix_2->patternType;
+}
+
+U_CDECL_END
+
+
+//#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\n", buf);
+}
+#define debug(x) printf("%s\n", 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"; // Deprecated - not used
+static const char fgNumberElements[]="NumberElements";
+static const char fgLatn[]="latn";
+static const char fgPatterns[]="patterns";
+static const char fgDecimalFormat[]="decimalFormat";
+static const char fgCurrencyFormat[]="currencyFormat";
+static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
+
+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) {
+ init();
+ 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) {
+ init();
+ 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) {
+ init();
+ 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) {
+ init();
+ 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) {
+ init();
+ UParseError parseError;
+ construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
+}
+
+//------------------------------------------------------------------------------
+// Constructs a DecimalFormat instance with the specified number format
+// pattern, the number format symbols, and the number format style.
+// The created instance owns the clone of the symbols.
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UNumberFormatStyle style,
+ UErrorCode& status) {
+ init();
+ fStyle = style;
+ UParseError parseError;
+ construct(status, parseError, &pattern, symbolsToAdopt);
+}
+
+//-----------------------------------------------------------------------------
+// Common DecimalFormat initialization.
+// Put all fields of an uninitialized object into a known state.
+// Common code, shared by all constructors.
+void
+DecimalFormat::init() {
+ fPosPrefixPattern = 0;
+ fPosSuffixPattern = 0;
+ fNegPrefixPattern = 0;
+ fNegSuffixPattern = 0;
+ fCurrencyChoice = 0;
+ fMultiplier = NULL;
+ fGroupingSize = 0;
+ fGroupingSize2 = 0;
+ fDecimalSeparatorAlwaysShown = FALSE;
+ fSymbols = NULL;
+ fUseSignificantDigits = FALSE;
+ fMinSignificantDigits = 1;
+ fMaxSignificantDigits = 6;
+ fUseExponentialNotation = FALSE;
+ fMinExponentDigits = 0;
+ fExponentSignAlwaysShown = FALSE;
+ fRoundingIncrement = 0;
+ fRoundingMode = kRoundHalfEven;
+ fPad = 0;
+ fFormatWidth = 0;
+ fPadPosition = kPadBeforePrefix;
+ fStyle = UNUM_DECIMAL;
+ fCurrencySignCount = 0;
+ fAffixPatternsForCurrency = NULL;
+ fAffixesForCurrency = NULL;
+ fPluralAffixesForCurrency = NULL;
+ fCurrencyPluralInfo = NULL;
+}
+
+//------------------------------------------------------------------------------
+// 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!!!
+ fRoundingIncrement = NULL;
+ fRoundingMode = kRoundHalfEven;
+ fPad = kPatternPadEscape;
+ fPadPosition = kPadBeforePrefix;
+ if (U_FAILURE(status))
+ return;
+
+ fPosPrefixPattern = fPosSuffixPattern = NULL;
+ fNegPrefixPattern = fNegSuffixPattern = NULL;
+ setMultiplier(1);
+ fGroupingSize = 3;
+ fGroupingSize2 = 0;
+ fDecimalSeparatorAlwaysShown = 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_getByKeyWithFallback(resource, fgNumberElements, resource, &status);
+ // TODO : Get the pattern based on the active numbering system for the locale. Right now assumes "latn".
+ resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status);
+ resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
+ const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &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 {
+ setCurrencyInternally(NULL, status);
+ }
+
+ const UnicodeString* patternUsed;
+ UnicodeString currencyPluralPatternForOther;
+ // apply pattern
+ if (fStyle == UNUM_CURRENCY_PLURAL) {
+ fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // the pattern used in format is not fixed until formatting,
+ // in which, the number is known and
+ // will be used to pick the right pattern based on plural count.
+ // Here, set the pattern as the pattern of plural count == "other".
+ // For most locale, the patterns are probably the same for all
+ // plural count. If not, the right pattern need to be re-applied
+ // during format.
+ fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther);
+ patternUsed = &currencyPluralPatternForOther;
+ // TODO: not needed?
+ setCurrencyForSymbols();
+
+ } else {
+ patternUsed = pattern;
+ }
+
+ if (patternUsed->indexOf(kCurrencySign) != -1) {
+ // initialize for currency, not only for plural format,
+ // but also for mix parsing
+ if (fCurrencyPluralInfo == NULL) {
+ fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ // need it for mix parsing
+ setupCurrencyAffixPatterns(status);
+ // expanded affixes for plural names
+ if (patternUsed->indexOf(fgTripleCurrencySign, 3, 0) != -1) {
+ setupCurrencyAffixes(*patternUsed, TRUE, TRUE, status);
+ }
+ }
+
+ applyPatternWithoutExpandAffix(*patternUsed,FALSE, parseErr, status);
+
+ // expand affixes
+ if (fCurrencySignCount != fgCurrencySignCountInPluralFormat) {
+ expandAffixAdjustWidth(NULL);
+ }
+
+ // If it was a currency format, apply the appropriate rounding by
+ // resetting the currency. NOTE: this copies fCurrency on top of itself.
+ if (fCurrencySignCount > fgCurrencySignCountZero) {
+ setCurrencyInternally(getCurrency(), status);
+ }
+}
+
+
+void
+DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UParseError parseErr;
+ fAffixPatternsForCurrency = initHashForAffixPattern(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Save the default currency patterns of this locale.
+ // Here, chose onlyApplyPatternWithoutExpandAffix without
+ // expanding the affix patterns into affixes.
+ UnicodeString currencyPattern;
+ UErrorCode error = U_ZERO_ERROR;
+
+ UResourceBundle *resource = ures_open(NULL, fSymbols->getLocale().getName(), &error);
+ resource = ures_getByKeyWithFallback(resource, fgNumberElements, resource, &error);
+ // TODO : Get the pattern based on the active numbering system for the locale. Right now assumes "latn".
+ resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &error);
+ resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
+ int32_t patLen = 0;
+ const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
+ ures_close(resource);
+
+ if (U_SUCCESS(error)) {
+ applyPatternWithoutExpandAffix(UnicodeString(patResStr, patLen), false,
+ parseErr, status);
+ AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
+ *fNegPrefixPattern,
+ *fNegSuffixPattern,
+ *fPosPrefixPattern,
+ *fPosSuffixPattern,
+ UCURR_SYMBOL_NAME);
+ fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status);
+ }
+
+ // save the unique currency plural patterns of this locale.
+ Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern;
+ const UHashElement* element = NULL;
+ int32_t pos = -1;
+ Hashtable pluralPatternSet;
+ while ((element = pluralPtn->nextElement(pos)) != NULL) {
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ if (pluralPatternSet.geti(*value) != 1) {
+ pluralPatternSet.puti(*value, 1, status);
+ applyPatternWithoutExpandAffix(*value, false, parseErr, status);
+ AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
+ *fNegPrefixPattern,
+ *fNegSuffixPattern,
+ *fPosPrefixPattern,
+ *fPosSuffixPattern,
+ UCURR_LONG_NAME);
+ fAffixPatternsForCurrency->put(*key, affixPtn, status);
+ }
+ }
+}
+
+
+void
+DecimalFormat::setupCurrencyAffixes(const UnicodeString& pattern,
+ UBool setupForCurrentPattern,
+ UBool setupForPluralPattern,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UParseError parseErr;
+ if (setupForCurrentPattern) {
+ if (fAffixesForCurrency) {
+ deleteHashForAffix(fAffixesForCurrency);
+ }
+ fAffixesForCurrency = initHashForAffix(status);
+ if (U_SUCCESS(status)) {
+ applyPatternWithoutExpandAffix(pattern, false, parseErr, status);
+ const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules();
+ StringEnumeration* keywords = pluralRules->getKeywords(status);
+ if (U_SUCCESS(status)) {
+ const UnicodeString* pluralCount;
+ while ((pluralCount = keywords->snext(status)) != NULL) {
+ if ( U_SUCCESS(status) ) {
+ expandAffixAdjustWidth(pluralCount);
+ AffixesForCurrency* affix = new AffixesForCurrency(
+ fNegativePrefix, fNegativeSuffix, fPositivePrefix, fPositiveSuffix);
+ fAffixesForCurrency->put(*pluralCount, affix, status);
+ }
+ }
+ }
+ delete keywords;
+ }
+ }
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (setupForPluralPattern) {
+ if (fPluralAffixesForCurrency) {
+ deleteHashForAffix(fPluralAffixesForCurrency);
+ }
+ fPluralAffixesForCurrency = initHashForAffix(status);
+ if (U_SUCCESS(status)) {
+ const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules();
+ StringEnumeration* keywords = pluralRules->getKeywords(status);
+ if (U_SUCCESS(status)) {
+ const UnicodeString* pluralCount;
+ while ((pluralCount = keywords->snext(status)) != NULL) {
+ if ( U_SUCCESS(status) ) {
+ UnicodeString ptn;
+ fCurrencyPluralInfo->getCurrencyPluralPattern(*pluralCount, ptn);
+ applyPatternInternally(*pluralCount, ptn, false, parseErr, status);
+ AffixesForCurrency* affix = new AffixesForCurrency(
+ fNegativePrefix, fNegativeSuffix, fPositivePrefix, fPositiveSuffix);
+ fPluralAffixesForCurrency->put(*pluralCount, affix, status);
+ }
+ }
+ }
+ delete keywords;
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------------
+
+DecimalFormat::~DecimalFormat()
+{
+ delete fPosPrefixPattern;
+ delete fPosSuffixPattern;
+ delete fNegPrefixPattern;
+ delete fNegSuffixPattern;
+ delete fCurrencyChoice;
+ delete fMultiplier;
+ delete fSymbols;
+ delete fRoundingIncrement;
+ deleteHashForAffixPattern();
+ deleteHashForAffix(fAffixesForCurrency);
+ deleteHashForAffix(fPluralAffixesForCurrency);
+ delete fCurrencyPluralInfo;
+}
+
+//------------------------------------------------------------------------------
+// copy constructor
+
+DecimalFormat::DecimalFormat(const DecimalFormat &source) :
+ NumberFormat(source) {
+ init();
+ *this = source;
+}
+
+//------------------------------------------------------------------------------
+// assignment operator
+
+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();
+ }
+ setRoundingIncrement(rhs.getRoundingIncrement());
+ fRoundingMode = rhs.fRoundingMode;
+ setMultiplier(rhs.getMultiplier());
+ 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*/
+ fCurrencySignCount = rhs.fCurrencySignCount;
+ /*end of Update*/
+ fMinExponentDigits = rhs.fMinExponentDigits;
+
+ /* sfb 990629 */
+ fFormatWidth = rhs.fFormatWidth;
+ fPad = rhs.fPad;
+ fPadPosition = rhs.fPadPosition;
+ /* end sfb */
+ fMinSignificantDigits = rhs.fMinSignificantDigits;
+ fMaxSignificantDigits = rhs.fMaxSignificantDigits;
+ fUseSignificantDigits = rhs.fUseSignificantDigits;
+ fFormatPattern = rhs.fFormatPattern;
+ fStyle = rhs.fStyle;
+ fCurrencySignCount = rhs.fCurrencySignCount;
+ if (rhs.fCurrencyPluralInfo) {
+ delete fCurrencyPluralInfo;
+ fCurrencyPluralInfo = rhs.fCurrencyPluralInfo->clone();
+ }
+ if (rhs.fAffixPatternsForCurrency) {
+ UErrorCode status = U_ZERO_ERROR;
+ deleteHashForAffixPattern();
+ fAffixPatternsForCurrency = initHashForAffixPattern(status);
+ copyHashForAffixPattern(rhs.fAffixPatternsForCurrency,
+ fAffixPatternsForCurrency, status);
+ }
+ if (rhs.fAffixesForCurrency) {
+ UErrorCode status = U_ZERO_ERROR;
+ deleteHashForAffix(fAffixesForCurrency);
+ fAffixesForCurrency = initHashForAffixPattern(status);
+ copyHashForAffix(rhs.fAffixesForCurrency, fAffixesForCurrency, status);
+ }
+ if (rhs.fPluralAffixesForCurrency) {
+ UErrorCode status = U_ZERO_ERROR;
+ deleteHashForAffix(fPluralAffixesForCurrency);
+ fPluralAffixesForCurrency = initHashForAffixPattern(status);
+ copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status);
+ }
+ }
+ 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::!=");
+ } else {
+ 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 (getMultiplier() != other->getMultiplier()) {
+ if (first) { printf("[ "); first = FALSE; }
+ printf("Multiplier %ld != %ld", getMultiplier(), other->getMultiplier());
+ }
+ 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 (fUseSignificantDigits != other->fUseSignificantDigits) {
+ debug("fUseSignificantDigits !=");
+ }
+ if (fUseSignificantDigits &&
+ fMinSignificantDigits != other->fMinSignificantDigits) {
+ debug("fMinSignificantDigits !=");
+ }
+ if (fUseSignificantDigits &&
+ fMaxSignificantDigits != other->fMaxSignificantDigits) {
+ debug("fMaxSignificantDigits !=");
+ }
+
+ if (!first) { printf(" ]"); }
+ if (fCurrencySignCount != other->fCurrencySignCount) {
+ debug("fCurrencySignCount !=");
+ }
+ if (fCurrencyPluralInfo == other->fCurrencyPluralInfo) {
+ debug("fCurrencyPluralInfo == ");
+ if (fCurrencyPluralInfo == NULL) {
+ debug("fCurrencyPluralInfo == NULL");
+ }
+ }
+ if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
+ *fCurrencyPluralInfo != *(other->fCurrencyPluralInfo)) {
+ debug("fCurrencyPluralInfo !=");
+ }
+ if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo == NULL ||
+ fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo != NULL) {
+ debug("fCurrencyPluralInfo one NULL, the other not");
+ }
+ if (fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo == NULL) {
+ debug("fCurrencyPluralInfo == ");
+ }
+ }
+#endif
+
+ return (NumberFormat::operator==(that) &&
+ ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ?
+ (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) :
+ (((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)) &&
+ getMultiplier() == other->getMultiplier() &&
+ 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)) &&
+ fCurrencySignCount == other->fCurrencySignCount &&
+ ((fCurrencyPluralInfo == other->fCurrencyPluralInfo &&
+ fCurrencyPluralInfo == NULL) ||
+ (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
+ *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo))));
+}
+
+//------------------------------------------------------------------------------
+
+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(int32_t number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const
+{
+ return format((int64_t)number, appendTo, posIter, status);
+}
+
+//------------------------------------------------------------------------------
+
+UnicodeString&
+DecimalFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const
+{
+ FieldPositionOnlyHandler handler(fieldPosition);
+ return _format(number, appendTo, handler);
+}
+
+UnicodeString&
+DecimalFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const
+{
+ FieldPositionIteratorHandler handler(posIter, status);
+ return _format(number, appendTo, handler);
+}
+
+UnicodeString&
+DecimalFormat::_format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPositionHandler& handler) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DigitList digits;
+ digits.set(number);
+ return _format(digits, appendTo, handler, status);
+}
+
+//------------------------------------------------------------------------------
+
+UnicodeString&
+DecimalFormat::format( double number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const
+{
+ FieldPositionOnlyHandler handler(fieldPosition);
+ return _format(number, appendTo, handler);
+}
+
+UnicodeString&
+DecimalFormat::format( double number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const
+{
+ FieldPositionIteratorHandler handler(posIter, status);
+ return _format(number, appendTo, handler);
+}
+
+UnicodeString&
+DecimalFormat::_format( double number,
+ UnicodeString& appendTo,
+ FieldPositionHandler& handler) const
+{
+ // Special case for NaN, sets the begin and end index to be the
+ // the string length of localized name of NaN.
+ // TODO: let NaNs go through DigitList.
+ if (uprv_isNaN(number))
+ {
+ int begin = appendTo.length();
+ appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+
+ handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+ addPadding(appendTo, handler, 0, 0);
+ return appendTo;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ DigitList digits;
+ digits.set(number);
+ _format(digits, appendTo, handler, status);
+ // No way to return status from here.
+ return appendTo;
+}
+
+//------------------------------------------------------------------------------
+
+
+UnicodeString&
+DecimalFormat::format(const StringPiece &number,
+ UnicodeString &toAppendTo,
+ FieldPositionIterator *posIter,
+ UErrorCode &status) const
+{
+ DigitList dnum;
+ dnum.set(number, status);
+ if (U_FAILURE(status)) {
+ return toAppendTo;
+ }
+ FieldPositionIteratorHandler handler(posIter, status);
+ _format(dnum, toAppendTo, handler, status);
+ return toAppendTo;
+}
+
+
+UnicodeString&
+DecimalFormat::format(const DigitList &number,
+ UnicodeString &appendTo,
+ FieldPositionIterator *posIter,
+ UErrorCode &status) const {
+ FieldPositionIteratorHandler handler(posIter, status);
+ _format(number, appendTo, handler, status);
+ return appendTo;
+}
+
+
+
+UnicodeString&
+DecimalFormat::format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode &status) const {
+ FieldPositionOnlyHandler handler(pos);
+ _format(number, appendTo, handler, status);
+ return appendTo;
+}
+
+
+
+UnicodeString&
+DecimalFormat::_format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPositionHandler& handler,
+ UErrorCode &status) const
+{
+ // Special case for NaN, sets the begin and end index to be the
+ // the string length of localized name of NaN.
+ if (number.isNaN())
+ {
+ int begin = appendTo.length();
+ appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+
+ handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+ addPadding(appendTo, handler, 0, 0);
+ return appendTo;
+ }
+
+ // Do this BEFORE checking to see if value is infinite or negative! Sets the
+ // begin and end index to be length of the string composed of
+ // localized name of Infinite and the positive/negative localized
+ // signs.
+
+ DigitList adjustedNum(number); // Copy, so we do not alter the original.
+ adjustedNum.setRoundingMode(fRoundingMode);
+ if (fMultiplier != NULL) {
+ adjustedNum.mult(*fMultiplier, status);
+ }
+
+ /*
+ * Note: sign is important for zero as well as non-zero numbers.
+ * 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 = !adjustedNum.isPositive();
+
+ // Apply rounding after multiplier
+
+ adjustedNum.fContext.status &= ~DEC_Inexact;
+ if (fRoundingIncrement != NULL) {
+ adjustedNum.div(*fRoundingIncrement, status);
+ adjustedNum.toIntegralValue();
+ adjustedNum.mult(*fRoundingIncrement, status);
+ adjustedNum.trim();
+ }
+ if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
+ status = U_FORMAT_INEXACT_ERROR;
+ return appendTo;
+ }
+
+
+ // Special case for INFINITE,
+ if (adjustedNum.isInfinite()) {
+ int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
+
+ int begin = appendTo.length();
+ appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
+
+ handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+ int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
+
+ addPadding(appendTo, handler, prefixLen, suffixLen);
+ return appendTo;
+ }
+
+ if (fUseExponentialNotation || areSignificantDigitsUsed()) {
+ int32_t sigDigits = precision();
+ if (sigDigits > 0) {
+ adjustedNum.round(sigDigits);
+ }
+ } else {
+ // Fixed point format. Round to a set number of fraction digits.
+ int32_t numFractionDigits = precision();
+ adjustedNum.roundFixedPoint(numFractionDigits);
+ }
+ if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
+ status = U_FORMAT_INEXACT_ERROR;
+ return appendTo;
+ }
+
+ return subformat(appendTo, handler, adjustedNum, FALSE);
+}
+
+
+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 DigitList must
+ * be filled in with the correct digits.
+ */
+UnicodeString&
+DecimalFormat::subformat(UnicodeString& appendTo,
+ FieldPositionHandler& handler,
+ DigitList& digits,
+ UBool isInteger) const
+{
+ // char zero = '0';
+ // DigitList returns digits as '0' thru '9', so we will need to
+ // always need to subtract the character 0 to get the numeric value to use for indexing.
+
+ UChar32 localizedDigits[10];
+ localizedDigits[0] = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+ localizedDigits[1] = getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
+ localizedDigits[2] = getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
+ localizedDigits[3] = getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
+ localizedDigits[4] = getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
+ localizedDigits[5] = getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
+ localizedDigits[6] = getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
+ localizedDigits[7] = getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
+ localizedDigits[8] = getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
+ localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
+
+ const UnicodeString *grouping ;
+ if(fCurrencySignCount > fgCurrencySignCountZero) {
+ grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
+ }else{
+ grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ }
+ const UnicodeString *decimal;
+ if(fCurrencySignCount > fgCurrencySignCountZero) {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ } else {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ }
+ UBool useSigDig = areSignificantDigitsUsed();
+ int32_t maxIntDig = getMaximumIntegerDigits();
+ int32_t minIntDig = getMinimumIntegerDigits();
+
+ // Appends the prefix.
+ double doubleValue = digits.getDouble();
+ int32_t prefixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), TRUE);
+
+ if (fUseExponentialNotation)
+ {
+ int currentLength = appendTo.length();
+ int intBegin = currentLength;
+ int intEnd = -1;
+ int fracBegin = -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.
+ digits.reduce(); // Removes trailing zero digits.
+ int32_t exponent = digits.getDecimalAt();
+ 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.getDecimalAt() - exponent;
+ int32_t totalDigits = digits.getCount();
+ 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)
+ {
+ intEnd = appendTo.length();
+ handler.addAttribute(kIntegerField, intBegin, intEnd);
+
+ appendTo += *decimal;
+
+ fracBegin = appendTo.length();
+ handler.addAttribute(kDecimalSeparatorField, fracBegin - 1, fracBegin);
+ }
+ // Restores the digit character or pads the buffer with zeros.
+ UChar32 c = (UChar32)((i < digits.getCount()) ?
+ localizedDigits[digits.getDigitValue(i)] :
+ localizedDigits[0]);
+ appendTo += c;
+ }
+
+ currentLength = appendTo.length();
+
+ if (intEnd < 0) {
+ handler.addAttribute(kIntegerField, intBegin, currentLength);
+ }
+ if (fracBegin > 0) {
+ handler.addAttribute(kFractionField, fracBegin, currentLength);
+ }
+
+ // 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);
+
+ handler.addAttribute(kExponentSymbolField, currentLength, appendTo.length());
+ currentLength = appendTo.length();
+
+ // 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);
+ handler.addAttribute(kExponentSignField, currentLength, appendTo.length());
+ } else if (fExponentSignAlwaysShown) {
+ appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ handler.addAttribute(kExponentSignField, currentLength, appendTo.length());
+ }
+
+ currentLength = appendTo.length();
+
+ DigitList expDigits;
+ expDigits.set(exponent);
+ {
+ int expDig = fMinExponentDigits;
+ if (fUseExponentialNotation && expDig < 1) {
+ expDig = 1;
+ }
+ for (i=expDigits.getDecimalAt(); i<expDig; ++i)
+ appendTo += (localizedDigits[0]);
+ }
+ for (i=0; i<expDigits.getDecimalAt(); ++i)
+ {
+ UChar32 c = (UChar32)((i < expDigits.getCount()) ?
+ localizedDigits[expDigits.getDigitValue(i)] :
+ localizedDigits[0]);
+ appendTo += c;
+ }
+
+ handler.addAttribute(kExponentField, currentLength, appendTo.length());
+ }
+ else // Not using exponential notation
+ {
+ int currentLength = appendTo.length();
+ int intBegin = currentLength;
+
+ 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.getDecimalAt()) : minIntDig;
+ if (digits.getDecimalAt() > 0 && count < digits.getDecimalAt()) {
+ count = digits.getDecimalAt();
+ }
+
+ // 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.getDecimalAt() - count;
+ }
+
+ int32_t sizeBeforeIntegerPart = appendTo.length();
+
+ int32_t i;
+ for (i=count-1; i>=0; --i)
+ {
+ if (i < digits.getDecimalAt() && digitIndex < digits.getCount() &&
+ sigCount < maxSigDig) {
+ // Output a real digit
+ appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)];
+ ++sigCount;
+ }
+ else
+ {
+ // Output a zero (leading or trailing)
+ appendTo += localizedDigits[0];
+ if (sigCount > 0) {
+ ++sigCount;
+ }
+ }
+
+ // Output grouping separator if necessary.
+ if (isGroupingPosition(i)) {
+ currentLength = appendTo.length();
+ appendTo.append(*grouping);
+ handler.addAttribute(kGroupingSeparatorField, currentLength, appendTo.length());
+ }
+ }
+
+ // TODO(dlf): this looks like it was a bug, we marked the int field as ending
+ // before the zero was generated.
+ // 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.getCount()) ||
+ (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 += localizedDigits[0];
+
+ currentLength = appendTo.length();
+ handler.addAttribute(kIntegerField, intBegin, currentLength);
+
+ // Output the decimal separator if we always do so.
+ if (fDecimalSeparatorAlwaysShown || fractionPresent) {
+ appendTo += *decimal;
+ handler.addAttribute(kDecimalSeparatorField, currentLength, appendTo.length());
+ currentLength = appendTo.length();
+ }
+
+ int fracBegin = currentLength;
+
+ count = useSigDig ? INT32_MAX : getMaximumFractionDigits();
+ if (useSigDig && (sigCount == maxSigDig ||
+ (sigCount >= minSigDig && digitIndex == digits.getCount()))) {
+ 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.getCount())) {
+ 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.getDecimalAt()-1)) {
+ appendTo += localizedDigits[0];
+ 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.getCount()) {
+ appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)];
+ } else {
+ appendTo += localizedDigits[0];
+ }
+
+ // 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.getCount() && sigCount >= minSigDig))) {
+ break;
+ }
+ }
+
+ handler.addAttribute(kFractionField, fracBegin, appendTo.length());
+ }
+
+ int32_t suffixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), FALSE);
+
+ addPadding(appendTo, handler, 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,
+ FieldPositionHandler& handler,
+ 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) {
+ handler.shiftLast(len);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+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();
+
+ // clear any old contents in the result. In particular, clears any DigitList
+ // that it may be holding.
+ result.setLong(0);
+
+ // Handle NaN as a special case:
+
+ // Skip padding characters, if around prefix
+ if (fFormatWidth > 0 && (fPadPosition == kPadBeforePrefix ||
+ fPadPosition == kPadAfterPrefix)) {
+ i = skipPadding(text, i);
+ }
+
+ if (isLenient()) {
+ // skip any leading whitespace
+ i = backup = skipUWhiteSpace(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;
+ parsePosition.setIndex(i);
+
+ // status is used to record whether a number is infinite.
+ UBool status[fgStatusLength];
+ UChar curbuf[4];
+ UChar* currency = parseCurrency ? curbuf : NULL;
+ DigitList *digits = new DigitList;
+ if (digits == NULL) {
+ return; // no way to report error from here.
+ }
+
+ if (fCurrencySignCount > fgCurrencySignCountZero) {
+ if (!parseForCurrency(text, parsePosition, *digits,
+ status, currency)) {
+ delete digits;
+ return;
+ }
+ } else {
+ if (!subparse(text,
+ fNegPrefixPattern, fNegSuffixPattern,
+ fPosPrefixPattern, fPosSuffixPattern,
+ FALSE, UCURR_SYMBOL_NAME,
+ parsePosition, *digits, status, currency)) {
+ parsePosition.setIndex(backup);
+ delete digits;
+ return;
+ }
+ }
+
+ // Handle infinity
+ if (status[fgStatusInfinite]) {
+ double inf = uprv_getInfinity();
+ result.setDouble(digits->isPositive() ? inf : -inf);
+ delete digits; // TODO: set the dl to infinity, and let it fall into the code below.
+ }
+
+ else {
+
+ if (fMultiplier != NULL) {
+ UErrorCode ec = U_ZERO_ERROR;
+ digits->div(*fMultiplier, ec);
+ }
+
+ // Negative zero special case:
+ // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
+ // if not parsing integerOnly, leave as -0, which a double can represent.
+ if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) {
+ digits->setPositive(TRUE);
+ }
+ result.adoptDigitList(digits);
+ }
+
+ 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
+ }
+}
+
+
+
+UBool
+DecimalFormat::parseForCurrency(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ DigitList& digits,
+ UBool* status,
+ UChar* currency) const {
+ int origPos = parsePosition.getIndex();
+ int maxPosIndex = origPos;
+ int maxErrorPos = -1;
+ // First, parse against current pattern.
+ // Since current pattern could be set by applyPattern(),
+ // it could be an arbitrary pattern, and it may not be the one
+ // defined in current locale.
+ UBool tmpStatus[fgStatusLength];
+ ParsePosition tmpPos(origPos);
+ DigitList tmpDigitList;
+ UBool found;
+ if (fStyle == UNUM_CURRENCY_PLURAL) {
+ found = subparse(text,
+ fNegPrefixPattern, fNegSuffixPattern,
+ fPosPrefixPattern, fPosSuffixPattern,
+ TRUE, UCURR_LONG_NAME,
+ tmpPos, tmpDigitList, tmpStatus, currency);
+ } else {
+ found = subparse(text,
+ fNegPrefixPattern, fNegSuffixPattern,
+ fPosPrefixPattern, fPosSuffixPattern,
+ TRUE, UCURR_SYMBOL_NAME,
+ tmpPos, tmpDigitList, tmpStatus, currency);
+ }
+ if (found) {
+ if (tmpPos.getIndex() > maxPosIndex) {
+ maxPosIndex = tmpPos.getIndex();
+ for (int32_t i = 0; i < fgStatusLength; ++i) {
+ status[i] = tmpStatus[i];
+ }
+ digits = tmpDigitList;
+ }
+ } else {
+ maxErrorPos = tmpPos.getErrorIndex();
+ }
+ // Then, parse against affix patterns.
+ // Those are currency patterns and currency plural patterns.
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
+ const UHashTok valueTok = element->value;
+ const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer;
+ UBool tmpStatus[fgStatusLength];
+ ParsePosition tmpPos(origPos);
+ DigitList tmpDigitList;
+ UBool result = subparse(text,
+ &affixPtn->negPrefixPatternForCurrency,
+ &affixPtn->negSuffixPatternForCurrency,
+ &affixPtn->posPrefixPatternForCurrency,
+ &affixPtn->posSuffixPatternForCurrency,
+ TRUE, affixPtn->patternType,
+ tmpPos, tmpDigitList, tmpStatus, currency);
+ if (result) {
+ found = true;
+ if (tmpPos.getIndex() > maxPosIndex) {
+ maxPosIndex = tmpPos.getIndex();
+ for (int32_t i = 0; i < fgStatusLength; ++i) {
+ status[i] = tmpStatus[i];
+ }
+ digits = tmpDigitList;
+ }
+ } else {
+ maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
+ tmpPos.getErrorIndex() : maxErrorPos;
+ }
+ }
+ // Finally, parse against simple affix to find the match.
+ // For example, in TestMonster suite,
+ // if the to-be-parsed text is "-\u00A40,00".
+ // complexAffixCompare will not find match,
+ // since there is no ISO code matches "\u00A4",
+ // and the parse stops at "\u00A4".
+ // We will just use simple affix comparison (look for exact match)
+ // to pass it.
+ UBool tmpStatus_2[fgStatusLength];
+ ParsePosition tmpPos_2(origPos);
+ DigitList tmpDigitList_2;
+ // set currencySignCount to 0 so that compareAffix function will
+ // fall to compareSimpleAffix path, not compareComplexAffix path.
+ // ?? TODO: is it right? need "false"?
+ UBool result = subparse(text,
+ &fNegativePrefix, &fNegativeSuffix,
+ &fPositivePrefix, &fPositiveSuffix,
+ FALSE, UCURR_SYMBOL_NAME,
+ tmpPos_2, tmpDigitList_2, tmpStatus_2,
+ currency);
+ if (result) {
+ if (tmpPos_2.getIndex() > maxPosIndex) {
+ maxPosIndex = tmpPos_2.getIndex();
+ for (int32_t i = 0; i < fgStatusLength; ++i) {
+ status[i] = tmpStatus_2[i];
+ }
+ digits = tmpDigitList_2;
+ }
+ found = true;
+ } else {
+ maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ?
+ tmpPos_2.getErrorIndex() : maxErrorPos;
+ }
+
+ if (!found) {
+ //parsePosition.setIndex(origPos);
+ parsePosition.setErrorIndex(maxErrorPos);
+ } else {
+ parsePosition.setIndex(maxPosIndex);
+ parsePosition.setErrorIndex(-1);
+ }
+ return found;
+}
+
+
+/**
+ * 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 negPrefix negative prefix.
+ * @param negSuffix negative suffix.
+ * @param posPrefix positive prefix.
+ * @param posSuffix positive suffix.
+ * @param currencyParsing whether it is currency parsing or not.
+ * @param type the currency type to parse against, LONG_NAME only or not.
+ * @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,
+ const UnicodeString* negPrefix,
+ const UnicodeString* negSuffix,
+ const UnicodeString* posPrefix,
+ const UnicodeString* posSuffix,
+ UBool currencyParsing,
+ int8_t type,
+ ParsePosition& parsePosition,
+ DigitList& digits, UBool* status,
+ UChar* currency) const
+{
+ // The parsing process builds up the number as char string, in the neutral format that
+ // will be acceptable to the decNumber library, then at the end passes that string
+ // off for conversion to a decNumber.
+ UErrorCode err = U_ZERO_ERROR;
+ CharString parsedNum;
+ digits.setToZero();
+
+ int32_t position = parsePosition.getIndex();
+ int32_t oldStart = position;
+ UBool strictParse = !isLenient();
+
+ // 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, posPrefix, currencyParsing, type, currency);
+ int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, currencyParsing, type, currency);
+ if (posMatch >= 0 && negMatch >= 0) {
+ if (posMatch > negMatch) {
+ negMatch = -1;
+ } else if (negMatch > posMatch) {
+ posMatch = -1;
+ }
+ }
+ if (posMatch >= 0) {
+ position += posMatch;
+ parsedNum.append('+', err);
+ } else if (negMatch >= 0) {
+ position += negMatch;
+ parsedNum.append('-', err);
+ } else if (strictParse){
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ // Match padding before prefix
+ if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) {
+ position = skipPadding(text, position);
+ }
+
+ if (! strictParse) {
+ position = skipUWhiteSpace(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] = infLen != 0;
+
+ if (infLen != 0) {
+ parsedNum.append("Infinity", err);
+ } else {
+ // 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.
+
+ UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+
+ UBool strictFail = FALSE; // did we exit with a strict parse failure?
+ int32_t lastGroup = -1; // where did we last see a grouping separator?
+ int32_t digitStart = position;
+ int32_t gs2 = fGroupingSize2 == 0 ? fGroupingSize : fGroupingSize2;
+
+ const UnicodeString *decimalString;
+ if (fCurrencySignCount > fgCurrencySignCountZero) {
+ decimalString = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ } else {
+ decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ }
+ UChar32 decimalChar = decimalString->char32At(0);
+
+ const UnicodeString *groupingString = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ UChar32 groupingChar = groupingString->char32At(0);
+ 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 decimalStringLength = decimalString->length();
+ int32_t decimalCharLength = U16_LENGTH(decimalChar);
+ int32_t groupingStringLength = groupingString->length();
+ int32_t groupingCharLength = U16_LENGTH(groupingChar);
+
+ // equivalent grouping and decimal support
+ // TODO markdavis Cache these if it makes a difference in performance.
+ UnicodeSet decimalFallback;
+ UnicodeSet *decimalSet = NULL;
+ UnicodeSet *groupingSet = NULL;
+
+ if (decimalCharLength == decimalStringLength) {
+ decimalSet = (UnicodeSet *) DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse, &decimalFallback)->cloneAsThawed();
+ }
+
+ if (groupingCharLength == groupingStringLength) {
+ if (strictParse) {
+ groupingSet = (UnicodeSet *) DecimalFormatStaticSets::gStaticSets->fStrictDefaultGroupingSeparators->cloneAsThawed();
+ } else {
+ groupingSet = (UnicodeSet *) DecimalFormatStaticSets::gStaticSets->fDefaultGroupingSeparators->cloneAsThawed();
+ }
+
+ groupingSet->add(groupingChar);
+
+ if (decimalSet != NULL) {
+ groupingSet->removeAll(*decimalSet);
+ }
+ }
+
+ // we are guaranteed that
+ // decimalSet contains the decimal, and
+ // groupingSet contains the groupingSeparator
+ // (unless decimal and grouping are the same, which should never happen. But in that case, groupingSet will just be empty.)
+
+ // We have to track digitCount ourselves, because digits.fCount will
+ // pin when the maximum allowable digits is reached.
+ int32_t digitCount = 0;
+ int32_t integerDigitCount = 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);
+ }
+
+ // As a last resort, look through the localized digits if the zero digit
+ // is not a "standard" Unicode digit.
+ if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) {
+ digit = 0;
+ if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kZeroDigitSymbol)).char32At(0) == ch ) {
+ break;
+ }
+ for (digit = 1 ; digit < 10 ; digit++ ) {
+ if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) {
+ break;
+ }
+ }
+ }
+
+ if (digit >= 0 && digit <= 9)
+ {
+ if (strictParse && backup != -1) {
+ // comma followed by digit, so group before comma is a
+ // secondary group. If there was a group separator
+ // before that, the group must == the secondary group
+ // length, else it can be <= the the secondary group
+ // length.
+ if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) ||
+ (lastGroup == -1 && position - digitStart - 1 > gs2)) {
+ strictFail = TRUE;
+ break;
+ }
+
+ lastGroup = backup;
+ }
+
+ // Cancel out backup setting (see grouping handler below)
+ backup = -1;
+ sawDigit = TRUE;
+
+ // Note: this will append leading zeros
+ parsedNum.append((char)(digit + '0'), err);
+
+ // count any digit that's not a leading zero
+ if (digit > 0 || digitCount > 0 || sawDecimal) {
+ digitCount += 1;
+
+ // count any integer digit that's not a leading zero
+ if (! sawDecimal) {
+ integerDigitCount += 1;
+ }
+ }
+
+ position += U16_LENGTH(ch);
+ }
+ else if (groupingStringLength > 0 && matchSymbol(text, position, groupingStringLength, *groupingString, groupingSet, ch) && isGroupingUsed())
+ {
+ if (sawDecimal) {
+ break;
+ }
+
+ if (strictParse) {
+ if ((!sawDigit || backup != -1)) {
+ // leading group, or two group separators in a row
+ strictFail = TRUE;
+ break;
+ }
+ }
+
+ // 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 += groupingStringLength;
+
+ if (groupingSet != NULL) {
+ // Once we see a grouping character, we only accept that grouping character from then on.
+ groupingSet->set(ch, ch);
+ }
+ }
+ else if (matchSymbol(text, position, decimalStringLength, *decimalString, decimalSet, ch))
+ {
+ if (strictParse) {
+ if (backup != -1 ||
+ (lastGroup != -1 && position - lastGroup != fGroupingSize + 1)) {
+ strictFail = TRUE;
+ break;
+ }
+ }
+
+ // If we're only parsing integers, or if we ALREADY saw the
+ // decimal, then don't parse this one.
+ if (isParseIntegerOnly() || sawDecimal) {
+ break;
+ }
+
+ parsedNum.append('.', err);
+ position += decimalStringLength;
+ sawDecimal = TRUE;
+
+ if (decimalSet != NULL) {
+ // Once we see a decimal character, we only accept that decimal character from then on.
+ decimalSet->set(ch, ch);
+ }
+ }
+ 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();
+ char exponentSign = '+';
+
+ 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))
+ {
+ exponentSign = '-';
+ pos += tmp->length();
+ }
+ }
+ }
+
+ UBool sawExponentDigit = 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) {
+ if (!sawExponentDigit) {
+ parsedNum.append('E', err);
+ parsedNum.append(exponentSign, err);
+ sawExponentDigit = TRUE;
+ }
+ ++pos;
+ parsedNum.append((char)(digit + '0'), err);
+ } else {
+ break;
+ }
+ }
+
+ if (sawExponentDigit) {
+ position = pos; // Advance past the exponent
+ }
+
+ break; // Whether we fail or succeed, we exit this loop
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ delete groupingSet;
+ delete decimalSet;
+
+ if (backup != -1)
+ {
+ position = backup;
+ }
+
+ if (strictParse && !sawDecimal) {
+ if (lastGroup != -1 && position - lastGroup != fGroupingSize + 1) {
+ strictFail = TRUE;
+ }
+ }
+
+ if (strictFail) {
+ // only set with strictParse and a grouping separator error
+
+ parsePosition.setIndex(oldStart);
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ // If there was no decimal point we have an integer
+
+ // 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);
+ }
+
+ int32_t posSuffixMatch = -1, negSuffixMatch = -1;
+
+ // Match positive and negative suffixes; prefer longest match.
+ if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
+ posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, type, currency);
+ }
+ if (negMatch >= 0) {
+ negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, type, currency);
+ }
+ if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
+ if (posSuffixMatch > negSuffixMatch) {
+ negSuffixMatch = -1;
+ } else if (negSuffixMatch > posSuffixMatch) {
+ posSuffixMatch = -1;
+ }
+ }
+
+ // Fail if neither or both
+ if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0));
+
+ // Match padding before suffix
+ if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) {
+ position = skipPadding(text, position);
+ }
+
+ parsePosition.setIndex(position);
+
+ parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
+
+ if(parsePosition.getIndex() == oldStart)
+ {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+ digits.set(parsedNum.toStringPiece(), err);
+
+ if (U_FAILURE(err)) {
+ 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 affixPat affix pattern used for currency affix comparison.
+ * @param currencyParsing whether it is currency parsing or not
+ * @param type the currency type to parse against, LONG_NAME only or not.
+ * @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,
+ const UnicodeString* affixPat,
+ UBool currencyParsing,
+ int8_t type,
+ UChar* currency) const
+{
+ const UnicodeString *patternToCompare;
+ if (fCurrencyChoice != NULL || currency != NULL ||
+ (fCurrencySignCount > fgCurrencySignCountZero && currencyParsing)) {
+
+ if (affixPat != NULL) {
+ return compareComplexAffix(*affixPat, text, pos, type, currency);
+ }
+ }
+
+ if (isNegative) {
+ if (isPrefix) {
+ patternToCompare = &fNegativePrefix;
+ }
+ else {
+ patternToCompare = &fNegativeSuffix;
+ }
+ }
+ else {
+ if (isPrefix) {
+ patternToCompare = &fPositivePrefix;
+ }
+ else {
+ patternToCompare = &fPositiveSuffix;
+ }
+ }
+ return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
+}
+
+/**
+ * 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,
+ UBool lenient) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t start = pos;
+ UChar32 affixChar = affix.char32At(0);
+ int32_t affixLength = affix.length();
+ int32_t inputLength = input.length();
+ int32_t affixCharLength = U16_LENGTH(affixChar);
+ UnicodeSet *affixSet;
+
+ DecimalFormatStaticSets::initSets(&status);
+
+ if (!lenient) {
+ affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents;
+
+ // If the affix is exactly one character long and that character
+ // is in the dash set and the very next input character is also
+ // in the dash set, return a match.
+ if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
+ if (affixSet->contains(input.char32At(pos))) {
+ return 1;
+ }
+ }
+
+ for (int32_t i = 0; i < affixLength; ) {
+ UChar32 c = affix.char32At(i);
+ int32_t len = U16_LENGTH(c);
+ if (PatternProps::isWhiteSpace(c)) {
+ // We may have a pattern like: \u200F \u0020
+ // and input text like: \u200F \u0020
+ // Note that U+200F and U+0020 are Pattern_White_Space but only
+ // U+0020 is UWhiteSpace. So we have to first do a direct
+ // match of the run of Pattern_White_Space in the pattern,
+ // then match any extra characters.
+ UBool literalMatch = FALSE;
+ while (pos < inputLength &&
+ input.char32At(pos) == c) {
+ literalMatch = TRUE;
+ i += len;
+ pos += len;
+ if (i == affixLength) {
+ break;
+ }
+ c = affix.char32At(i);
+ len = U16_LENGTH(c);
+ if (!PatternProps::isWhiteSpace(c)) {
+ break;
+ }
+ }
+
+ // Advance over run in pattern
+ i = skipPatternWhiteSpace(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;
+ }
+
+ // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
+ // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
+ // is also in the affix.
+ i = skipUWhiteSpace(affix, i);
+ } else {
+ if (pos < inputLength &&
+ input.char32At(pos) == c) {
+ i += len;
+ pos += len;
+ } else {
+ return -1;
+ }
+ }
+ }
+ } else {
+ UBool match = FALSE;
+
+ affixSet = DecimalFormatStaticSets::gStaticSets->fDashEquivalents;
+
+ if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
+ pos = skipUWhiteSpace(input, pos);
+
+ if (affixSet->contains(input.char32At(pos))) {
+ return pos - start + 1;
+ }
+ }
+
+ for (int32_t i = 0; i < affixLength; )
+ {
+ //i = skipRuleWhiteSpace(affix, i);
+ i = skipUWhiteSpace(affix, i);
+ pos = skipUWhiteSpace(input, pos);
+
+ if (i >= affixLength || pos >= inputLength) {
+ break;
+ }
+
+ UChar32 c = affix.char32At(i);
+ int32_t len = U16_LENGTH(c);
+
+ if (input.char32At(pos) != c) {
+ return -1;
+ }
+
+ match = TRUE;
+ i += len;
+ pos += len;
+ }
+
+ if (affixLength > 0 && ! match) {
+ return -1;
+ }
+ }
+ return pos - start;
+}
+
+/**
+ * Skip over a run of zero or more Pattern_White_Space characters at
+ * pos in text.
+ */
+int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) {
+ const UChar* s = text.getBuffer();
+ return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
+}
+
+/**
+ * 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 type the currency type to parse against, LONG_NAME only or not.
+ * @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,
+ int8_t type,
+ UChar* currency) const
+{
+ int32_t start = pos;
+ U_ASSERT(currency != NULL ||
+ (fCurrencyChoice != NULL && *getCurrency() != 0) ||
+ fCurrencySignCount > fgCurrencySignCountZero);
+
+ 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: {
+ // since the currency names in choice format is saved
+ // the same way as other currency names,
+ // do not need to do currency choice parsing here.
+ // the general currency parsing parse against all names,
+ // including names in choice format.
+ UBool intl = i<affixPat.length() &&
+ affixPat.char32At(i) == kCurrencySign;
+ if (intl) {
+ ++i;
+ }
+ UBool plural = i<affixPat.length() &&
+ affixPat.char32At(i) == kCurrencySign;
+ if (plural) {
+ ++i;
+ intl = FALSE;
+ }
+ // Parse generic currency -- anything for which we
+ // have a display name, or any 3-letter ISO code.
+ // Try to parse display name for our locale; first
+ // determine our locale.
+ const char* loc = fCurrencyPluralInfo->getLocale().getName();
+ ParsePosition ppos(pos);
+ UChar curr[4];
+ UErrorCode ec = U_ZERO_ERROR;
+ // Delegate parse of display name => ISO code to Currency
+ uprv_parseCurrency(loc, text, ppos, type, curr, ec);
+
+ // If parse succeeds, populate currency[0]
+ if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
+ if (currency) {
+ u_strcpy(currency, curr);
+ } else {
+ // The formatter is currency-style but the client has not requested
+ // the value of the parsed currency. In this case, if that value does
+ // not match the formatter's current value, then the parse fails.
+ UChar effectiveCurr[4];
+ getEffectiveCurrency(effectiveCurr, ec);
+ if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) {
+ pos = -1;
+ continue;
+ }
+ }
+ pos = ppos.getIndex();
+ } else if (!isLenient()){
+ pos = -1;
+ }
+ 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 (PatternProps::isWhiteSpace(c)) {
+ i = skipPatternWhiteSpace(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
+ * ch is a Pattern_White_Space then match a run of white space in text.
+ */
+int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) {
+ if (PatternProps::isWhiteSpace(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 = skipPatternWhiteSpace(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 (PatternProps::isWhiteSpace(ch)) {
+ i = skipPatternWhiteSpace(str, i);
+ }
+ pos = match(text, pos, ch);
+ }
+ return pos;
+}
+
+UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol,
+ UnicodeSet *sset, UChar32 schar)
+{
+ if (sset != NULL) {
+ return sset->contains(schar);
+ }
+
+ return text.compare(position, length, symbol) == 0;
+}
+
+
+//------------------------------------------------------------------------------
+// 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(NULL);
+}
+//------------------------------------------------------------------------------
+// Setting the symbols is equlivalent to adopting a newly created localized
+// symbols.
+
+void
+DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
+{
+ adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
+}
+
+
+const CurrencyPluralInfo*
+DecimalFormat::getCurrencyPluralInfo(void) const
+{
+ return fCurrencyPluralInfo;
+}
+
+
+void
+DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt)
+{
+ if (toAdopt != NULL) {
+ delete fCurrencyPluralInfo;
+ fCurrencyPluralInfo = toAdopt;
+ // re-set currency affix patterns and currency affixes.
+ if (fCurrencySignCount > fgCurrencySignCountZero) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (fAffixPatternsForCurrency) {
+ deleteHashForAffixPattern();
+ }
+ setupCurrencyAffixPatterns(status);
+ if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
+ // only setup the affixes of the plural pattern.
+ setupCurrencyAffixes(fFormatPattern, FALSE, TRUE, status);
+ }
+ }
+ }
+}
+
+void
+DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info)
+{
+ adoptCurrencyPluralInfo(info.clone());
+}
+
+
+/**
+ * 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) == UnicodeString(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!
+ setCurrencyInternally(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.
+// Multipliers are stored as decimal numbers (DigitLists) because that
+// is the most convenient for muliplying or dividing the numbers to be formatted.
+// A NULL multiplier implies one, and the scaling operations are skipped.
+
+int32_t
+DecimalFormat::getMultiplier() const
+{
+ if (fMultiplier == NULL) {
+ return 1;
+ } else {
+ return fMultiplier->getLong();
+ }
+}
+
+//------------------------------------------------------------------------------
+// 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) {
+ newValue = 1; // one being the benign default value for a multiplier.
+ }
+ if (newValue == 1) {
+ delete fMultiplier;
+ fMultiplier = NULL;
+ } else {
+ if (fMultiplier == NULL) {
+ fMultiplier = new DigitList;
+ }
+ if (fMultiplier != NULL) {
+ fMultiplier->set(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
+ */
+double DecimalFormat::getRoundingIncrement() const {
+ if (fRoundingIncrement == NULL) {
+ return 0.0;
+ } else {
+ return fRoundingIncrement->getDouble();
+ }
+}
+
+/**
+ * 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();
+ }
+ if (fRoundingIncrement != NULL) {
+ fRoundingIncrement->set(newValue);
+ return;
+ }
+ }
+ // These statements are executed if newValue is less than 0.0
+ // or fRoundingIncrement could not be created.
+ delete fRoundingIncrement;
+ fRoundingIncrement = NULL;
+}
+
+/**
+ * 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 UnicodeString(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.
+ * This method also will be called before formatting if format currency
+ * plural names, since the plural name is not a static one, it is
+ * based on the currency plural count, the affix will be known only
+ * after the currency plural count is know.
+ * In which case, the parameter
+ * 'pluralCount' will be a non-null currency plural count.
+ * In all other cases, the 'pluralCount' is null, which means it is not needed.
+ */
+void DecimalFormat::expandAffixes(const UnicodeString* pluralCount) {
+ FieldPositionHandler none;
+ if (fPosPrefixPattern != 0) {
+ expandAffix(*fPosPrefixPattern, fPositivePrefix, 0, none, FALSE, pluralCount);
+ }
+ if (fPosSuffixPattern != 0) {
+ expandAffix(*fPosSuffixPattern, fPositiveSuffix, 0, none, FALSE, pluralCount);
+ }
+ if (fNegPrefixPattern != 0) {
+ expandAffix(*fNegPrefixPattern, fNegativePrefix, 0, none, FALSE, pluralCount);
+ }
+ if (fNegSuffixPattern != 0) {
+ expandAffix(*fNegSuffixPattern, fNegativeSuffix, 0, none, FALSE, pluralCount);
+ }
+#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. If CURRENCY_SIGN is tripled, it is interpreted as
+ * currency plural long names, such as "US Dollars".
+ * 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.
+ * @param pluralCount the plural count. It is only used for currency
+ * plural format. In which case, it is the plural
+ * count of the currency amount. For example,
+ * in en_US, it is the singular "one", or the plural
+ * "other". For all other cases, it is null, and
+ * is not being used.
+ */
+void DecimalFormat::expandAffix(const UnicodeString& pattern,
+ UnicodeString& affix,
+ double number,
+ FieldPositionHandler& handler,
+ UBool doFormat,
+ const UnicodeString* pluralCount) 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);
+ int beginIdx = affix.length();
+ 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;
+ UBool plural = FALSE;
+ if (intl) {
+ ++i;
+ plural = i<pattern.length() &&
+ pattern.char32At(i) == kCurrencySign;
+ if (plural) {
+ intl = FALSE;
+ ++i;
+ }
+ }
+ const UChar* currencyUChars = getCurrency();
+ if (currencyUChars[0] != 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ if (plural && pluralCount != NULL) {
+ // plural name is only needed when pluralCount != null,
+ // which means when formatting currency plural names.
+ // For other cases, pluralCount == null,
+ // and plural names are not needed.
+ int32_t len;
+ CharString pluralCountChar;
+ pluralCountChar.appendInvariantChars(*pluralCount, ec);
+ UBool isChoiceFormat;
+ const UChar* s = ucurr_getPluralName(currencyUChars,
+ fSymbols != NULL ? fSymbols->getLocale().getName() :
+ Locale::getDefault().getName(), &isChoiceFormat,
+ pluralCountChar.data(), &len, &ec);
+ affix += UnicodeString(s, len);
+ handler.addAttribute(kCurrencyField, beginIdx, affix.length());
+ } else if(intl) {
+ affix.append(currencyUChars, -1);
+ handler.addAttribute(kCurrencyField, beginIdx, affix.length());
+ } else {
+ int32_t len;
+ UBool isChoiceFormat;
+ // If fSymbols is NULL, use default locale
+ const UChar* s = ucurr_getName(currencyUChars,
+ fSymbols != NULL ? fSymbols->getLocale().getName() : Locale::getDefault().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(UnicodeString(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.append(currencyUChars, -1);
+ handler.addAttribute(kCurrencyField, beginIdx, affix.length());
+ }
+ }
+ continue;
+ }
+ affix += UnicodeString(s, len);
+ handler.addAttribute(kCurrencyField, beginIdx, affix.length());
+ }
+ } else {
+ if(intl) {
+ affix += getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ } else {
+ affix += getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
+ }
+ handler.addAttribute(kCurrencyField, beginIdx, affix.length());
+ }
+ break;
+ }
+ case kPatternPercent:
+ affix += getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
+ handler.addAttribute(kPercentField, beginIdx, affix.length());
+ break;
+ case kPatternPerMill:
+ affix += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
+ handler.addAttribute(kPermillField, beginIdx, affix.length());
+ break;
+ case kPatternPlus:
+ affix += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ handler.addAttribute(kSignField, beginIdx, affix.length());
+ break;
+ case kPatternMinus:
+ affix += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ handler.addAttribute(kSignField, beginIdx, affix.length());
+ 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,
+ FieldPositionHandler& handler,
+ UBool isNegative, UBool isPrefix) const {
+ // plural format precedes choice format
+ if (fCurrencyChoice != 0 &&
+ fCurrencySignCount != fgCurrencySignCountInPluralFormat) {
+ const UnicodeString* affixPat;
+ if (isPrefix) {
+ affixPat = isNegative ? fNegPrefixPattern : fPosPrefixPattern;
+ } else {
+ affixPat = isNegative ? fNegSuffixPattern : fPosSuffixPattern;
+ }
+ if (affixPat) {
+ UnicodeString affixBuf;
+ expandAffix(*affixPat, affixBuf, number, handler, TRUE, NULL);
+ buf.append(affixBuf);
+ return affixBuf.length();
+ }
+ // else someone called a function that reset the pattern.
+ }
+
+ const UnicodeString* affix;
+ if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
+ UnicodeString pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
+ AffixesForCurrency* oneSet;
+ if (fStyle == UNUM_CURRENCY_PLURAL) {
+ oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount);
+ } else {
+ oneSet = (AffixesForCurrency*)fAffixesForCurrency->get(pluralCount);
+ }
+ if (isPrefix) {
+ affix = isNegative ? &oneSet->negPrefixForCurrency :
+ &oneSet->posPrefixForCurrency;
+ } else {
+ affix = isNegative ? &oneSet->negSuffixForCurrency :
+ &oneSet->posSuffixForCurrency;
+ }
+ } else {
+ if (isPrefix) {
+ affix = isNegative ? &fNegativePrefix : &fPositivePrefix;
+ } else {
+ affix = isNegative ? &fNegativeSuffix : &fPositiveSuffix;
+ }
+ }
+
+ int32_t begin = (int) buf.length();
+
+ buf.append(*affix);
+
+ if (handler.isRecording()) {
+ int32_t offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol));
+ if (offset > -1) {
+ UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
+ handler.addAttribute(kCurrencyField, begin + offset, begin + offset + aff.length());
+ }
+
+ offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
+ if (offset > -1) {
+ UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ handler.addAttribute(kCurrencyField, begin + offset, begin + offset + aff.length());
+ }
+
+ offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol));
+ if (offset > -1) {
+ UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ handler.addAttribute(kSignField, begin + offset, begin + offset + aff.length());
+ }
+
+ offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol));
+ if (offset > -1) {
+ UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
+ handler.addAttribute(kPercentField, begin + offset, begin + offset + aff.length());
+ }
+
+ offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol));
+ if (offset > -1) {
+ UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
+ handler.addAttribute(kPermillField, begin + offset, begin + offset + aff.length());
+ }
+ }
+ 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
+{
+ if (fStyle == UNUM_CURRENCY_PLURAL) {
+ // the prefix or suffix pattern might not be defined yet,
+ // so they can not be synthesized,
+ // instead, get them directly.
+ // but it might not be the actual pattern used in formatting.
+ // the actual pattern used in formatting depends on the
+ // formatted number's plural count.
+ result = fFormatPattern;
+ return result;
+ }
+ 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->getCount(); ++i) {
+ roundingDigits.append(zero+(fRoundingIncrement->getDigitValue(i))); // Convert to Unicode digit
+ }
+ roundingDecimalPos = fRoundingIncrement->getDecimalAt();
+ }
+ 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::applyPatternWithoutExpandAffix(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;
+
+ // 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
+ if ((pos+1) < pattern.length() &&
+ pattern[pos+1] == kCurrencySign) {
+ affix->append(kCurrencySign);
+ ++pos; // Skip over the doubled character
+ fCurrencySignCount = fgCurrencySignCountInPluralFormat;
+ } else {
+ fCurrencySignCount = fgCurrencySignCountInISOFormat;
+ }
+ } else {
+ fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
+ }
+ // 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;
+ 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;
+ setMultiplier(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.setDecimalAt(effectiveDecimalPos - roundingPos);
+ if (fRoundingIncrement != NULL) {
+ *fRoundingIncrement = roundingInc;
+ } else {
+ fRoundingIncrement = new DigitList(roundingInc);
+ /* test for NULL */
+ if (fRoundingIncrement == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete fPosPrefixPattern;
+ delete fPosSuffixPattern;
+ return;
+ }
+ }
+ fRoundingIncrement->getDouble(); // forces caching of double in the DigitList,
+ // makes getting it thread safe.
+ 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;
+ fCurrencySignCount = 0;
+ setGroupingUsed(FALSE);
+ fGroupingSize = 0;
+ fGroupingSize2 = 0;
+ setMultiplier(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
+
+ // save the pattern
+ fFormatPattern = pattern;
+}
+
+
+void
+DecimalFormat::expandAffixAdjustWidth(const UnicodeString* pluralCount) {
+ expandAffixes(pluralCount);
+ if (fFormatWidth > 0) {
+ // Finish computing format width (see above)
+ // TODO: how to handle fFormatWidth,
+ // need to save in f(Plural)AffixesForCurrecy?
+ fFormatWidth += fPositivePrefix.length() + fPositiveSuffix.length();
+ }
+}
+
+
+void
+DecimalFormat::applyPattern(const UnicodeString& pattern,
+ UBool localized,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ // do the following re-set first. since they change private data by
+ // apply pattern again.
+ if (pattern.indexOf(kCurrencySign) != -1) {
+ if (fCurrencyPluralInfo == NULL) {
+ // initialize currencyPluralInfo if needed
+ fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
+ }
+ if (fAffixPatternsForCurrency == NULL) {
+ setupCurrencyAffixPatterns(status);
+ }
+ if (pattern.indexOf(fgTripleCurrencySign, 3, 0) != -1) {
+ // only setup the affixes of the current pattern.
+ setupCurrencyAffixes(pattern, TRUE, FALSE, status);
+ }
+ }
+ applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
+ expandAffixAdjustWidth(NULL);
+}
+
+
+void
+DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount,
+ const UnicodeString& pattern,
+ UBool localized,
+ UParseError& parseError,
+ UErrorCode& status) {
+ applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
+ expandAffixAdjustWidth(&pluralCount);
+}
+
+
+/**
+ * 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::setCurrencyInternally(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 (fCurrencySignCount > fgCurrencySignCountZero && isCurr) {
+ rounding = ucurr_getRoundingIncrement(theCurrency, &ec);
+ frac = ucurr_getDefaultFractionDigits(theCurrency, &ec);
+ }
+
+ NumberFormat::setCurrency(theCurrency, ec);
+ if (U_FAILURE(ec)) return;
+
+ if (fCurrencySignCount > fgCurrencySignCountZero) {
+ // NULL or empty currency is *legal* and indicates no currency.
+ if (isCurr) {
+ setRoundingIncrement(rounding);
+ setMinimumFractionDigits(frac);
+ setMaximumFractionDigits(frac);
+ }
+ expandAffixes(NULL);
+ }
+}
+
+void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
+ // set the currency before compute affixes to get the right currency names
+ NumberFormat::setCurrency(theCurrency, ec);
+ if (fFormatPattern.indexOf(fgTripleCurrencySign, 3, 0) != -1) {
+ UnicodeString savedPtn = fFormatPattern;
+ setupCurrencyAffixes(fFormatPattern, TRUE, TRUE, ec);
+ UParseError parseErr;
+ applyPattern(savedPtn, FALSE, parseErr, ec);
+ }
+ // set the currency after apply pattern to get the correct rounding/fraction
+ setCurrencyInternally(theCurrency, ec);
+}
+
+// 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 {
+ if (fSymbols == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ ec = U_ZERO_ERROR;
+ 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() const {
+ if (areSignificantDigitsUsed()) {
+ return getMaximumSignificantDigits();
+ } else if (fUseExponentialNotation) {
+ return getMinimumIntegerDigits() + getMaximumFractionDigits();
+ } else {
+ return getMaximumFractionDigits();
+ }
+}
+
+
+// TODO: template algorithm
+Hashtable*
+DecimalFormat::initHashForAffix(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if ( U_FAILURE(status) ) {
+ delete hTable;
+ return NULL;
+ }
+ hTable->setValueComparator(decimfmtAffixValueComparator);
+ return hTable;
+}
+
+Hashtable*
+DecimalFormat::initHashForAffixPattern(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if ( U_FAILURE(status) ) {
+ delete hTable;
+ return NULL;
+ }
+ hTable->setValueComparator(decimfmtAffixPatternValueComparator);
+ return hTable;
+}
+
+void
+DecimalFormat::deleteHashForAffix(Hashtable*& table)
+{
+ if ( table == NULL ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = table->nextElement(pos)) != NULL ) {
+ const UHashTok valueTok = element->value;
+ const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer;
+ delete value;
+ }
+ delete table;
+ table = NULL;
+}
+
+
+
+void
+DecimalFormat::deleteHashForAffixPattern()
+{
+ if ( fAffixPatternsForCurrency == NULL ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
+ const UHashTok valueTok = element->value;
+ const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
+ delete value;
+ }
+ delete fAffixPatternsForCurrency;
+ fAffixPatternsForCurrency = NULL;
+}
+
+
+void
+DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
+ Hashtable* target,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
+ AffixPatternsForCurrency* copy = new AffixPatternsForCurrency(
+ value->negPrefixPatternForCurrency,
+ value->negSuffixPatternForCurrency,
+ value->posPrefixPatternForCurrency,
+ value->posSuffixPatternForCurrency,
+ value->patternType);
+ target->put(UnicodeString(*key), copy, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+ }
+}
+
+
+
+void
+DecimalFormat::copyHashForAffix(const Hashtable* source,
+ Hashtable* target,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+
+ const UHashTok valueTok = element->value;
+ const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer;
+ AffixesForCurrency* copy = new AffixesForCurrency(
+ value->negPrefixForCurrency,
+ value->negSuffixForCurrency,
+ value->posPrefixForCurrency,
+ value->posSuffixForCurrency);
+ target->put(UnicodeString(*key), copy, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/digitlst.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/digitlst.cpp
new file mode 100644
index 00000000000..1ae9027c747
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/digitlst.cpp
@@ -0,0 +1,875 @@
+/*
+**********************************************************************
+* Copyright (C) 1997-2011, 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 "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits>
+
+// ***************************************************************************
+// class DigitList
+// A wrapper onto decNumber.
+// Used to be standalone.
+// ***************************************************************************
+
+/**
+ * This is the zero digit. The base for the digits returned by getDigit()
+ * Note that it is the platform invariant digit, and is not Unicode.
+ */
+#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";
+
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+// default constructor
+
+DigitList::DigitList()
+{
+ uprv_decContextDefault(&fContext, DEC_INIT_BASE);
+ fContext.traps = 0;
+ uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
+ fContext.digits = fStorage.getCapacity();
+
+ fDecNumber = fStorage.getAlias();
+ uprv_decNumberZero(fDecNumber);
+
+ fDouble = 0.0;
+ fHaveDouble = TRUE;
+}
+
+// -------------------------------------
+
+DigitList::~DigitList()
+{
+}
+
+// -------------------------------------
+// copy constructor
+
+DigitList::DigitList(const DigitList &other)
+{
+ fDecNumber = fStorage.getAlias();
+ *this = other;
+}
+
+
+// -------------------------------------
+// assignment operator
+
+DigitList&
+DigitList::operator=(const DigitList& other)
+{
+ if (this != &other)
+ {
+ uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
+
+ if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
+ fDecNumber = fStorage.resize(other.fStorage.getCapacity());
+ }
+ // Always reset the fContext.digits, even if fDecNumber was not reallocated,
+ // because above we copied fContext from other.fContext.
+ fContext.digits = fStorage.getCapacity();
+ uprv_decNumberCopy(fDecNumber, other.fDecNumber);
+
+ fDouble = other.fDouble;
+ fHaveDouble = other.fHaveDouble;
+ }
+ return *this;
+}
+
+// -------------------------------------
+// operator == (does not exactly match the old DigitList function)
+
+UBool
+DigitList::operator==(const DigitList& that) const
+{
+ if (this == &that) {
+ return TRUE;
+ }
+ decNumber n; // Has space for only a none digit value.
+ decContext c;
+ uprv_decContextDefault(&c, DEC_INIT_BASE);
+ c.digits = 1;
+ c.traps = 0;
+
+ uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
+ UBool result = decNumberIsZero(&n);
+ return result;
+}
+
+// -------------------------------------
+// comparison function. Returns
+// Not Comparable : -2
+// < : -1
+// == : 0
+// > : +1
+int32_t DigitList::compare(const DigitList &other) {
+ decNumber result;
+ int32_t savedDigits = fContext.digits;
+ fContext.digits = 1;
+ uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
+ fContext.digits = savedDigits;
+ if (decNumberIsZero(&result)) {
+ return 0;
+ } else if (decNumberIsSpecial(&result)) {
+ return -2;
+ } else if (result.bits & DECNEG) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+
+// -------------------------------------
+// Reduce - remove trailing zero digits.
+void
+DigitList::reduce() {
+ uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
+}
+
+
+// -------------------------------------
+// trim - remove trailing fraction zero digits.
+void
+DigitList::trim() {
+ uprv_decNumberTrim(fDecNumber);
+}
+
+// -------------------------------------
+// Resets the digit list; sets all the digits to zero.
+
+void
+DigitList::clear()
+{
+ uprv_decNumberZero(fDecNumber);
+ uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
+ fDouble = 0.0;
+ fHaveDouble = TRUE;
+}
+
+
+/**
+ * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
+ * @param number The number to format
+ * @param outputStr The string to output to. Must be at least MAX_DIGITS+2 in length (21),
+ * to hold the longest int64_t value.
+ * @return the number of digits written, not including the sign.
+ */
+static int32_t
+formatBase10(int64_t number, char *outputStr) {
+ // The number is output backwards, starting with the LSD.
+ // Fill the buffer from the far end. After the number is complete,
+ // slide the string contents to the front.
+
+ const int32_t MAX_IDX = MAX_DIGITS+2;
+ int32_t destIdx = MAX_IDX;
+ outputStr[--destIdx] = 0;
+
+ int64_t n = number;
+ if (number < 0) { // Negative numbers are slightly larger than a postive
+ outputStr[--destIdx] = (char)(-(n % 10) + kZero);
+ n /= -10;
+ }
+ do {
+ outputStr[--destIdx] = (char)(n % 10 + kZero);
+ n /= 10;
+ } while (n > 0);
+
+ if (number < 0) {
+ outputStr[--destIdx] = '-';
+ }
+
+ // Slide the number to the start of the output str
+ U_ASSERT(destIdx >= 0);
+ int32_t length = MAX_IDX - destIdx;
+ uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
+
+ return length;
+}
+
+
+// -------------------------------------
+//
+// setRoundingMode()
+// For most modes, the meaning and names are the same between the decNumber library
+// (which DigitList follows) and the ICU Formatting Rounding Mode values.
+// The flag constants are different, however.
+//
+// Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList.
+// This mode, inherited from Java, means that numbers that would not format exactly
+// will return an error when formatting is attempted.
+
+void
+DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) {
+ enum rounding r;
+
+ switch (m) {
+ case DecimalFormat::kRoundCeiling: r = DEC_ROUND_CEILING; break;
+ case DecimalFormat::kRoundFloor: r = DEC_ROUND_FLOOR; break;
+ case DecimalFormat::kRoundDown: r = DEC_ROUND_DOWN; break;
+ case DecimalFormat::kRoundUp: r = DEC_ROUND_UP; break;
+ case DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break;
+ case DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break;
+ case DecimalFormat::kRoundHalfUp: r = DEC_ROUND_HALF_UP; break;
+ case DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break;
+ default:
+ // TODO: how to report the problem?
+ // Leave existing mode unchanged.
+ r = uprv_decContextGetRounding(&fContext);
+ }
+ uprv_decContextSetRounding(&fContext, r);
+
+}
+
+
+// -------------------------------------
+
+void
+DigitList::setPositive(UBool s) {
+ if (s) {
+ fDecNumber->bits &= ~DECNEG;
+ } else {
+ fDecNumber->bits |= DECNEG;
+ }
+ fHaveDouble = FALSE;
+}
+// -------------------------------------
+
+void
+DigitList::setDecimalAt(int32_t d) {
+ U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
+ U_ASSERT(d-1>-999999999);
+ U_ASSERT(d-1< 999999999);
+ int32_t adjustedDigits = fDecNumber->digits;
+ if (decNumberIsZero(fDecNumber)) {
+ // Account for difference in how zero is represented between DigitList & decNumber.
+ adjustedDigits = 0;
+ }
+ fDecNumber->exponent = d - adjustedDigits;
+ fHaveDouble = FALSE;
+}
+
+int32_t
+DigitList::getDecimalAt() {
+ U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
+ if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) {
+ return fDecNumber->exponent; // Exponent should be zero for these cases.
+ }
+ return fDecNumber->exponent + fDecNumber->digits;
+}
+
+void
+DigitList::setCount(int32_t c) {
+ U_ASSERT(c <= fContext.digits);
+ if (c == 0) {
+ // For a value of zero, DigitList sets all fields to zero, while
+ // decNumber keeps one digit (with that digit being a zero)
+ c = 1;
+ fDecNumber->lsu[0] = 0;
+ }
+ fDecNumber->digits = c;
+ fHaveDouble = FALSE;
+}
+
+int32_t
+DigitList::getCount() const {
+ if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) {
+ // The extra test for exponent==0 is needed because parsing sometimes appends
+ // zero digits. It's bogus, decimalFormatter parsing needs to be cleaned up.
+ return 0;
+ } else {
+ return fDecNumber->digits;
+ }
+}
+
+void
+DigitList::setDigit(int32_t i, char v) {
+ int32_t count = fDecNumber->digits;
+ U_ASSERT(i<count);
+ U_ASSERT(v>='0' && v<='9');
+ v &= 0x0f;
+ fDecNumber->lsu[count-i-1] = v;
+ fHaveDouble = FALSE;
+}
+
+char
+DigitList::getDigit(int32_t i) {
+ int32_t count = fDecNumber->digits;
+ U_ASSERT(i<count);
+ return fDecNumber->lsu[count-i-1] + '0';
+}
+
+// copied from DigitList::getDigit()
+uint8_t
+DigitList::getDigitValue(int32_t i) {
+ int32_t count = fDecNumber->digits;
+ U_ASSERT(i<count);
+ return fDecNumber->lsu[count-i-1];
+}
+
+// -------------------------------------
+// Appends the digit to the digit list if it's not out of scope.
+// Ignores the digit, otherwise.
+//
+// This function is horribly inefficient to implement with decNumber because
+// the digits are stored least significant first, which requires moving all
+// existing digits down one to make space for the new one to be appended.
+//
+void
+DigitList::append(char digit)
+{
+ U_ASSERT(digit>='0' && digit<='9');
+ // Ignore digits which exceed the precision we can represent
+ // And don't fix for larger precision. Fix callers instead.
+ if (decNumberIsZero(fDecNumber)) {
+ // Zero needs to be special cased because of the difference in the way
+ // that the old DigitList and decNumber represent it.
+ // digit cout was zero for digitList, is one for decNumber
+ fDecNumber->lsu[0] = digit & 0x0f;
+ fDecNumber->digits = 1;
+ fDecNumber->exponent--; // To match the old digit list implementation.
+ } else {
+ int32_t nDigits = fDecNumber->digits;
+ if (nDigits < fContext.digits) {
+ int i;
+ for (i=nDigits; i>0; i--) {
+ fDecNumber->lsu[i] = fDecNumber->lsu[i-1];
+ }
+ fDecNumber->lsu[0] = digit & 0x0f;
+ fDecNumber->digits++;
+ // DigitList emulation - appending doesn't change the magnitude of existing
+ // digits. With decNumber's decimal being after the
+ // least signficant digit, we need to adjust the exponent.
+ fDecNumber->exponent--;
+ }
+ }
+ fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+/**
+ * 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
+{
+ // TODO: fix thread safety. Can probably be finessed some by analyzing
+ // what public const functions can see which DigitLists.
+ // Like precompute fDouble for DigitLists coming in from a parse
+ // or from a Formattable::set(), but not for any others.
+ if (fHaveDouble) {
+ return fDouble;
+ }
+ DigitList *nonConstThis = const_cast<DigitList *>(this);
+
+ if (gDecimal == 0) {
+ 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];
+ }
+
+ if (isZero()) {
+ nonConstThis->fDouble = 0.0;
+ if (decNumberIsNegative(fDecNumber)) {
+ nonConstThis->fDouble /= -1;
+ }
+ } else if (isInfinite()) {
+ if (std::numeric_limits<double>::has_infinity) {
+ nonConstThis->fDouble = std::numeric_limits<double>::infinity();
+ } else {
+ nonConstThis->fDouble = std::numeric_limits<double>::max();
+ }
+ if (!isPositive()) {
+ nonConstThis->fDouble = -fDouble;
+ }
+ } else {
+ MaybeStackArray<char, MAX_DBL_DIGITS+18> s;
+ // Note: 14 is a magic constant from the decNumber library documentation,
+ // the max number of extra characters beyond the number of digits
+ // needed to represent the number in string form. Add a few more
+ // for the additional digits we retain.
+
+ // Round down to appx. double precision, if the number is longer than that.
+ // Copy the number first, so that we don't modify the original.
+ if (getCount() > MAX_DBL_DIGITS + 3) {
+ DigitList numToConvert(*this);
+ numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good.
+ numToConvert.round(MAX_DBL_DIGITS+3);
+ uprv_decNumberToString(numToConvert.fDecNumber, s);
+ // TODO: how many extra digits should be included for an accurate conversion?
+ } else {
+ uprv_decNumberToString(this->fDecNumber, s);
+ }
+ U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
+
+ if (gDecimal != '.') {
+ char *decimalPt = strchr(s, '.');
+ if (decimalPt != NULL) {
+ *decimalPt = gDecimal;
+ }
+ }
+ char *end = NULL;
+ nonConstThis->fDouble = uprv_strtod(s, &end);
+ }
+ nonConstThis->fHaveDouble = TRUE;
+ return fDouble;
+}
+
+// -------------------------------------
+
+/**
+ * convert this number to an int32_t. Round if there is a fractional part.
+ * Return zero if the number cannot be represented.
+ */
+int32_t DigitList::getLong() /*const*/
+{
+ int32_t result = 0;
+ if (fDecNumber->digits + fDecNumber->exponent > 10) {
+ // Overflow, absolute value too big.
+ return result;
+ }
+ if (fDecNumber->exponent != 0) {
+ // Force to an integer, with zero exponent, rounding if necessary.
+ // (decNumberToInt32 will only work if the exponent is exactly zero.)
+ DigitList copy(*this);
+ DigitList zero;
+ uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
+ result = uprv_decNumberToInt32(copy.fDecNumber, &fContext);
+ } else {
+ result = uprv_decNumberToInt32(fDecNumber, &fContext);
+ }
+ return result;
+}
+
+
+/**
+ * convert this number to an int64_t. Truncate if there is a fractional part.
+ * Return zero if the number cannot be represented.
+ */
+int64_t DigitList::getInt64() /*const*/ {
+ // Truncate if non-integer.
+ // Return 0 if out of range.
+ // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits)
+ //
+ if (fDecNumber->digits + fDecNumber->exponent > 19) {
+ // Overflow, absolute value too big.
+ return 0;
+ }
+
+ // The number of integer digits may differ from the number of digits stored
+ // in the decimal number.
+ // for 12.345 numIntDigits = 2, number->digits = 5
+ // for 12E4 numIntDigits = 6, number->digits = 2
+ // The conversion ignores the fraction digits in the first case,
+ // and fakes up extra zero digits in the second.
+ // TODO: It would be faster to store a table of powers of ten to multiply by
+ // instead of looping over zero digits, multiplying each time.
+
+ int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent;
+ uint64_t value = 0;
+ for (int32_t i = 0; i < numIntDigits; i++) {
+ // Loop is iterating over digits starting with the most significant.
+ // Numbers are stored with the least significant digit at index zero.
+ int32_t digitIndex = fDecNumber->digits - i - 1;
+ int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
+ value = value * (uint64_t)10 + (uint64_t)v;
+ }
+
+ if (decNumberIsNegative(fDecNumber)) {
+ value = ~value;
+ value += 1;
+ }
+ int64_t svalue = (int64_t)value;
+
+ // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of
+ // overflow can't wrap too far. The test will also fail -0, but
+ // that does no harm; the right answer is 0.
+ if (numIntDigits == 19) {
+ if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
+ (!decNumberIsNegative(fDecNumber) && svalue<0)) {
+ svalue = 0;
+ }
+ }
+
+ return svalue;
+}
+
+
+/**
+ * Return a string form of this number.
+ * Format is as defined by the decNumber library, for interchange of
+ * decimal numbers.
+ */
+void DigitList::getDecimal(CharString &str, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // A decimal number in string form can, worst case, be 14 characters longer
+ // than the number of digits. So says the decNumber library doc.
+ int32_t maxLength = fDecNumber->digits + 14;
+ int32_t capacity = 0;
+ char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
+ if (U_FAILURE(status)) {
+ return; // Memory allocation error on growing the string.
+ }
+ U_ASSERT(capacity >= maxLength);
+ uprv_decNumberToString(this->fDecNumber, buffer);
+ U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
+ str.append(buffer, -1, status);
+}
+
+/**
+ * Return true if this is an integer value that can be held
+ * by an int32_t type.
+ */
+UBool
+DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
+{
+ if (decNumberIsSpecial(this->fDecNumber)) {
+ // NaN or Infinity. Does not fit in int32.
+ return FALSE;
+ }
+ uprv_decNumberTrim(this->fDecNumber);
+ if (fDecNumber->exponent < 0) {
+ // Number contains fraction digits.
+ return FALSE;
+ }
+ if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
+ (fDecNumber->bits & DECNEG) != 0) {
+ // Negative Zero, not ingored. Cannot represent as a long.
+ return FALSE;
+ }
+ if (fDecNumber->digits + fDecNumber->exponent < 10) {
+ // The number is 9 or fewer digits.
+ // The max and min int32 are 10 digts, so this number fits.
+ // This is the common case.
+ return TRUE;
+ }
+
+ // TODO: Should cache these constants; construction is relatively costly.
+ // But not of huge consequence; they're only needed for 10 digit ints.
+ UErrorCode status = U_ZERO_ERROR;
+ DigitList min32; min32.set("-2147483648", status);
+ if (this->compare(min32) < 0) {
+ return FALSE;
+ }
+ DigitList max32; max32.set("2147483647", status);
+ if (this->compare(max32) > 0) {
+ return FALSE;
+ }
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ return true;
+}
+
+
+
+/**
+ * Return true if the number represented by this object can fit into
+ * a long.
+ */
+UBool
+DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
+{
+ if (decNumberIsSpecial(this->fDecNumber)) {
+ // NaN or Infinity. Does not fit in int32.
+ return FALSE;
+ }
+ uprv_decNumberTrim(this->fDecNumber);
+ if (fDecNumber->exponent < 0) {
+ // Number contains fraction digits.
+ return FALSE;
+ }
+ if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
+ (fDecNumber->bits & DECNEG) != 0) {
+ // Negative Zero, not ingored. Cannot represent as a long.
+ return FALSE;
+ }
+ if (fDecNumber->digits + fDecNumber->exponent < 19) {
+ // The number is 18 or fewer digits.
+ // The max and min int64 are 19 digts, so this number fits.
+ // This is the common case.
+ return TRUE;
+ }
+
+ // TODO: Should cache these constants; construction is relatively costly.
+ // But not of huge consequence; they're only needed for 19 digit ints.
+ UErrorCode status = U_ZERO_ERROR;
+ DigitList min64; min64.set("-9223372036854775808", status);
+ if (this->compare(min64) < 0) {
+ return FALSE;
+ }
+ DigitList max64; max64.set("9223372036854775807", status);
+ if (this->compare(max64) > 0) {
+ return FALSE;
+ }
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ return true;
+}
+
+
+// -------------------------------------
+
+void
+DigitList::set(int32_t source)
+{
+ set((int64_t)source);
+ fDouble = source;
+ fHaveDouble = TRUE;
+}
+
+// -------------------------------------
+/**
+ * @param maximumDigits The maximum digits to be generated. If zero,
+ * there is no maximum -- generate all digits.
+ */
+void
+DigitList::set(int64_t source)
+{
+ char str[MAX_DIGITS+2]; // Leave room for sign and trailing nul.
+ formatBase10(source, str);
+ U_ASSERT(uprv_strlen(str) < sizeof(str));
+
+ uprv_decNumberFromString(fDecNumber, str, &fContext);
+ fDouble = (double)source;
+ fHaveDouble = TRUE;
+}
+
+
+// -------------------------------------
+/**
+ * Set the DigitList from a decimal number string.
+ *
+ * The incoming string _must_ be nul terminated, even though it is arriving
+ * as a StringPiece because that is what the decNumber library wants.
+ * We can get away with this for an internal function; it would not
+ * be acceptable for a public API.
+ */
+void
+DigitList::set(const StringPiece &source, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Figure out a max number of digits to use during the conversion, and
+ // resize the number up if necessary.
+ int32_t numDigits = source.length();
+ if (numDigits > fContext.digits) {
+ // fContext.digits == fStorage.getCapacity()
+ decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
+ if (t == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fDecNumber = t;
+ fContext.digits = numDigits;
+ }
+
+ fContext.status = 0;
+ uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
+ if ((fContext.status & DEC_Conversion_syntax) != 0) {
+ status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
+ }
+ fHaveDouble = FALSE;
+}
+
+/**
+ * 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.
+ */
+void
+DigitList::set(double source)
+{
+ // 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)
+
+ // Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
+ sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
+ U_ASSERT(uprv_strlen(rep) < sizeof(rep));
+
+ // Create a decNumber from the string.
+ uprv_decNumberFromString(fDecNumber, rep, &fContext);
+ uprv_decNumberTrim(fDecNumber);
+ fDouble = source;
+ fHaveDouble = TRUE;
+}
+
+// -------------------------------------
+
+/*
+ * Multiply
+ * The number will be expanded if need be to retain full precision.
+ * In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
+ * will not be required for this use.
+ */
+void
+DigitList::mult(const DigitList &other, UErrorCode &status) {
+ fContext.status = 0;
+ int32_t requiredDigits = this->digits() + other.digits();
+ if (requiredDigits > fContext.digits) {
+ reduce(); // Remove any trailing zeros
+ int32_t requiredDigits = this->digits() + other.digits();
+ ensureCapacity(requiredDigits, status);
+ }
+ uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
+ fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+/*
+ * Divide
+ * The number will _not_ be expanded for inexact results.
+ * TODO: probably should expand some, for rounding increments that
+ * could add a few digits, e.g. .25, but not expand arbitrarily.
+ */
+void
+DigitList::div(const DigitList &other, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
+ fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+/*
+ * ensureCapacity. Grow the digit storage for the number if it's less than the requested
+ * amount. Never reduce it. Available size is kept in fContext.digits.
+ */
+void
+DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (requestedCapacity <= 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (requestedCapacity > DEC_MAX_DIGITS) {
+ // Don't report an error for requesting too much.
+ // Arithemetic Results will be rounded to what can be supported.
+ // At 999,999,999 max digits, exceeding the limit is not too likely!
+ requestedCapacity = DEC_MAX_DIGITS;
+ }
+ if (requestedCapacity > fContext.digits) {
+ decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
+ if (newBuffer == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fContext.digits = requestedCapacity;
+ fDecNumber = newBuffer;
+ }
+}
+
+// -------------------------------------
+
+/**
+ * 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)
+{
+ int32_t savedDigits = fContext.digits;
+ fContext.digits = maximumDigits;
+ uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
+ fContext.digits = savedDigits;
+ uprv_decNumberTrim(fDecNumber);
+ fHaveDouble = FALSE;
+}
+
+
+void
+DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
+ trim(); // Remove trailing zeros.
+ if (fDecNumber->exponent >= -maximumFractionDigits) {
+ return;
+ }
+ decNumber scale; // Dummy decimal number, but with the desired number of
+ uprv_decNumberZero(&scale); // fraction digits.
+ scale.exponent = -maximumFractionDigits;
+ scale.lsu[0] = 1;
+
+ uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
+ trim();
+ fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+void
+DigitList::toIntegralValue() {
+ uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
+}
+
+
+// -------------------------------------
+UBool
+DigitList::isZero() const
+{
+ return decNumberIsZero(fDecNumber);
+}
+
+
+U_NAMESPACE_END
+#endif // #if !UCONFIG_NO_FORMATTING
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/digitlst.h b/Build/source/libs/icu/icu-4.8.1/i18n/digitlst.h
new file mode 100644
index 00000000000..508f1b42478
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/digitlst.h
@@ -0,0 +1,400 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 1997-2011, 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>
+#include "decContext.h"
+#include "decNumber.h"
+#include "cmemory.h"
+
+// Decimal digits in a 64-bit int
+#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,
+ DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
+
+ // "+." + fDigits + "e" + fDecimalAt
+ MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
+} EDigitListValues;
+
+U_NAMESPACE_BEGIN
+
+class CharString;
+
+// Export an explicit template instantiation of the MaybeStackHeaderAndArray that
+// is used as a data member of DigitList.
+//
+// MSVC requires this, even though it should not be necessary.
+// No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
+//
+// Macintosh produces duplicate definition linker errors with the explicit template
+// instantiation.
+//
+#if !defined(U_DARWIN)
+template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
+#endif
+
+
+/**
+ * Digit List is actually a Decimal Floating Point number.
+ * The original implementation has been replaced by a thin wrapper onto a
+ * decimal number from the decNumber library.
+ *
+ * The original DigitList API has been retained, to minimize the impact of
+ * the change on the rest of the ICU formatting code.
+ *
+ * The change to decNumber enables support for big decimal numbers, and
+ * allows rounding computations to be done directly in decimal, avoiding
+ * extra, and inaccurate, conversions to and from doubles.
+ *
+ * Original DigitList comments:
+ *
+ * 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.
+ *
+ * --------
+ *
+ * DigitList vs. decimalNumber:
+ *
+ * DigitList stores digits with the most significant first.
+ * decNumber stores digits with the least significant first.
+ *
+ * DigitList, decimal point is before the most significant.
+ * decNumber, decimal point is after the least signficant digit.
+ *
+ * digitList: 0.ddddd * 10 ^ exp
+ * decNumber: ddddd. * 10 ^ exp
+ *
+ * digitList exponent = decNumber exponent + digit count
+ *
+ * digitList, digits are platform invariant chars, '0' - '9'
+ * decNumber, digits are binary, one per byte, 0 - 9.
+ *
+ * (decNumber library is configurable in how digits are stored, ICU has configured
+ * it this way for convenience in replacing the old DigitList implementation.)
+ */
+class U_I18N_API 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;
+
+ int32_t compare(const DigitList& other);
+
+
+ inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
+
+ /**
+ * 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);
+
+ /**
+ * Remove, by rounding, any fractional part of the decimal number,
+ * leaving an integer value.
+ */
+ void toIntegralValue();
+
+ /**
+ * Appends digits to the list.
+ * CAUTION: this function is not recommended for new code.
+ * In the original DigitList implementation, decimal numbers were
+ * parsed by appending them to a digit list as they were encountered.
+ * With the revamped DigitList based on decNumber, append is very
+ * inefficient, and the interaction with the exponent value is confusing.
+ * Best avoided.
+ * TODO: remove this function once all use has been replaced.
+ * TODO: describe alternative to append()
+ * @param digit The digit to be appended.
+ */
+ 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*/;
+
+ /**
+ * Utility routine to get the value of the digit list as a decimal string.
+ */
+ void getDecimal(CharString &str, UErrorCode &status);
+
+ /**
+ * 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.
+ * @param source The value to be set
+ */
+ void set(double source);
+
+ /**
+ * 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
+ */
+ void set(int32_t source);
+
+ /**
+ * 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
+ */
+ void set(int64_t source);
+
+ /**
+ * Utility routine to set the value of the digit list from a decimal number
+ * string.
+ * @param source The value to be set. The string must be nul-terminated.
+ */
+ void set(const StringPiece &source, UErrorCode &status);
+
+ /**
+ * Multiply this = this * arg
+ * This digitlist will be expanded if necessary to accomodate the result.
+ * @param arg the number to multiply by.
+ */
+ void mult(const DigitList &arg, UErrorCode &status);
+
+ /**
+ * Divide this = this / arg
+ */
+ void div(const DigitList &arg, UErrorCode &status);
+
+ // The following functions replace direct access to the original DigitList implmentation
+ // data structures.
+
+ void setRoundingMode(DecimalFormat::ERoundingMode m);
+
+ /** Test a number for zero.
+ * @return TRUE if the number is zero
+ */
+ UBool isZero(void) const;
+
+ /** Test for a Nan
+ * @return TRUE if the number is a NaN
+ */
+ UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
+
+ UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
+
+ /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
+ void reduce();
+
+ /** Remove trailing fraction zeros, adjust exponent accordingly. */
+ void trim();
+
+ /** Set to zero */
+ void setToZero() {uprv_decNumberZero(fDecNumber);}
+
+ /** get the number of digits in the decimal number */
+ int32_t digits() const {return fDecNumber->digits;}
+
+ /**
+ * Round the number 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);
+
+ void roundFixedPoint(int32_t maximumFractionDigits);
+
+ /** Ensure capacity for digits. Grow the storage if it is currently less than
+ * the requested size. Capacity is not reduced if it is already greater
+ * than requested.
+ */
+ void ensureCapacity(int32_t requestedSize, UErrorCode &status);
+
+ UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
+ void setPositive(UBool s);
+
+ void setDecimalAt(int32_t d);
+ int32_t getDecimalAt();
+
+ void setCount(int32_t c);
+ int32_t getCount() const;
+
+ /**
+ * Set the digit in platform (invariant) format, from '0'..'9'
+ * @param i index of digit
+ * @param v digit value, from '0' to '9' in platform invariant format
+ */
+ void setDigit(int32_t i, char v);
+
+ /**
+ * Get the digit in platform (invariant) format, from '0'..'9' inclusive
+ * @param i index of digit
+ * @return invariant format of the digit
+ */
+ char getDigit(int32_t i);
+
+
+ /**
+ * Get the digit's value, as an integer from 0..9 inclusive.
+ * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
+ * @param i index of digit
+ * @return value of that digit
+ */
+ uint8_t getDigitValue(int32_t i);
+
+
+private:
+ /*
+ * 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;
+ */
+
+public:
+ decContext fContext; // public access to status flags.
+
+private:
+ decNumber *fDecNumber;
+ MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage;
+
+ /* Cached double value corresponding to this decimal number.
+ * This is an optimization for the formatting implementation, which may
+ * ask for the double value multiple times.
+ */
+ double fDouble;
+ UBool fHaveDouble;
+
+
+
+ UBool shouldRoundUp(int32_t maximumDigits) const;
+};
+
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_FORMATTING
+#endif // _DIGITLST
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/dtfmtsym.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/dtfmtsym.cpp
new file mode 100644
index 00000000000..868ad9436c5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtfmtsym.cpp
@@ -0,0 +1,1606 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 "ureslocs.h"
+#include "tznames.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" */
+};
+
+// Not used now
+//// These are the zone strings of last resort.
+//static const UChar gLastResortZoneStrings[5][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" */
+//};
+
+static const UChar gLastResortGmtZero[] =
+ {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 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 gGmtZeroFormatTag[] = "gmtZeroFormat";
+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;
+ UBool failed = FALSE;
+
+ fZoneStrings = (UnicodeString **)uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString *));
+ if (fZoneStrings != NULL) {
+ for (row=0; row<fZoneStringsRowCount; ++row)
+ {
+ fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount);
+ if (fZoneStrings[row] == NULL) {
+ failed = TRUE;
+ break;
+ }
+ for (col=0; col<fZoneStringsColCount; ++col) {
+ // fastCopyFrom() - see assignArray comments
+ fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
+ }
+ }
+ }
+ // If memory allocation failed, roll back and delete fZoneStrings
+ if (failed) {
+ for (int i = row; i >= 0; i--) {
+ delete[] fZoneStrings[i];
+ }
+ uprv_free(fZoneStrings);
+ fZoneStrings = NULL;
+ }
+}
+
+/**
+ * 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(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount);
+ 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);
+ fGmtZero = other.fGmtZero;
+ 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
+ fLocaleZoneStrings = 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 (fNarrowEras) delete[] fNarrowEras;
+ 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);
+ }
+
+ fZoneStrings = NULL;
+ fLocaleZoneStrings = NULL;
+ fZoneStringsRowCount = 0;
+ fZoneStringsColCount = 0;
+}
+
+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 &&
+ fNarrowErasCount == other.fNarrowErasCount &&
+ 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 &&
+ fGmtZero == other.fGmtZero &&
+ fGmtFormat == other.fGmtFormat)
+ {
+ // Now compare the arrays themselves
+ if (arrayCompare(fEras, other.fEras, fErasCount) &&
+ arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) &&
+ arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) &&
+ 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::getNarrowEras(int32_t &count) const
+{
+ count = fNarrowErasCount;
+ return fNarrowEras;
+}
+
+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::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fNarrowEras)
+ delete[] fNarrowEras;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fNarrowEras = newUnicodeStringArray(count);
+ uprv_arrayCopy(narrowErasArray,fNarrowEras, count);
+ fNarrowErasCount = 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 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;
+}
+
+// For now, we include all zones
+#define ZONE_SET UCAL_ZONE_TYPE_ANY
+
+// This code must be called within a synchronized block
+void
+DateFormatSymbols::initZoneStringsArray(void) {
+ if (fZoneStrings != NULL || fLocaleZoneStrings != NULL) {
+ return;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ StringEnumeration *tzids = NULL;
+ UnicodeString ** zarray = NULL;
+ TimeZoneNames *tzNames = NULL;
+ int32_t rows = 0;
+
+ do { // dummy do-while
+
+ tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SET, NULL, NULL, status);
+ rows = tzids->count(status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+
+ // Allocate array
+ int32_t size = rows * sizeof(UnicodeString*);
+ zarray = (UnicodeString**)uprv_malloc(size);
+ if (zarray == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ uprv_memset(zarray, 0, size);
+
+ tzNames = TimeZoneNames::createInstance(fZSFLocale, status);
+
+ const UnicodeString *tzid;
+ int32_t i = 0;
+ UDate now = Calendar::getNow();
+ UnicodeString tzDispName;
+
+ while ((tzid = tzids->snext(status))) {
+ if (U_FAILURE(status)) {
+ break;
+ }
+
+ zarray[i] = new UnicodeString[5];
+ if (zarray[i] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+ zarray[i][0].setTo(*tzid);
+ zarray[i][1].setTo(tzNames->getDisplayName(*tzid, UTZNM_LONG_STANDARD, now, tzDispName));
+ zarray[i][2].setTo(tzNames->getDisplayName(*tzid, UTZNM_SHORT_STANDARD, now, tzDispName));
+ zarray[i][3].setTo(tzNames->getDisplayName(*tzid, UTZNM_LONG_DAYLIGHT, now, tzDispName));
+ zarray[i][4].setTo(tzNames->getDisplayName(*tzid, UTZNM_SHORT_DAYLIGHT, now, tzDispName));
+ i++;
+ }
+
+ } while (FALSE);
+
+ if (U_FAILURE(status)) {
+ if (zarray) {
+ for (int32_t i = 0; i < rows; i++) {
+ if (zarray[i]) {
+ delete[] zarray[i];
+ }
+ }
+ uprv_free(zarray);
+ }
+ }
+
+ if (tzNames) {
+ delete tzNames;
+ }
+ if (tzids) {
+ delete tzids;
+ }
+
+ fLocaleZoneStrings = zarray;
+ fZoneStringsRowCount = rows;
+ fZoneStringsColCount = 5;
+}
+
+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();
+ // 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;
+ fNarrowEras = NULL;
+ fNarrowErasCount = 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;
+
+ // 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 *zoneBundle = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
+ UResourceBundle *zoneStringsArray = ures_getByKeyWithFallback(zoneBundle, gZoneStringsTag, NULL, &status);
+
+ // load the first data item
+ UResourceBundle *erasMain = calData.getByKey(gErasTag, status);
+ UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, 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, gNamesAbbrTag, NULL, &status);
+ }
+ // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too
+ oldStatus = status;
+ UResourceBundle *narrowEras = ures_getByKeyWithFallback(erasMain, gNamesNarrowTag, NULL, &status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) {
+ status = oldStatus;
+ narrowEras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, 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(&fNarrowEras, fNarrowErasCount, (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);
+ fGmtZero.setTo(TRUE, gLastResortGmtZero, -1);
+ 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(&fNarrowEras, fNarrowErasCount, narrowEras, 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 zero
+ resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gGmtZeroFormatTag, &len, &status);
+ if (len > 0) {
+ fGmtZero.setTo(TRUE, resStr, len);
+ }
+
+ // 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, (int32_t)(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] + UNICODE_STRING_SIMPLE(":ss");
+ } else if (fGmtHourFormats[GMT_NEGATIVE_HM].indexOf((UChar)0x002E /* '.' */) != -1) {
+ fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE(".ss");
+ } else {
+ fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE("ss");
+ }
+ if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
+ fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE(":ss");
+ } else if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x002E /* '.' */) != -1) {
+ fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE(".ss");
+ } else {
+ fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE("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(narrowEras);
+ ures_close(zoneStringsArray);
+ ures_close(zoneBundle);
+}
+
+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-4.8.1/i18n/dtitv_impl.h b/Build/source/libs/icu/icu-4.8.1/i18n/dtitv_impl.h
new file mode 100644
index 00000000000..009d9a8b4ae
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtitv_impl.h
@@ -0,0 +1,93 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITV_IMPL.H
+*
+*******************************************************************************
+*/
+
+
+#ifndef DTITV_IMPL_H__
+#define DTITV_IMPL_H__
+
+/**
+ * \file
+ * \brief C++ API: Defines macros for interval format implementation
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+
+
+#define QUOTE ((UChar)0x0027)
+#define LOW_LINE ((UChar)0x005F)
+#define COLON ((UChar)0x003A)
+#define LEFT_CURLY_BRACKET ((UChar)0x007B)
+#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
+#define SPACE ((UChar)0x0020)
+#define EN_DASH ((UChar)0x2013)
+
+#define DIGIT_ZERO ((UChar)0x0030)
+#define DIGIT_ONE ((UChar)0x0031)
+
+#define LOW_A ((UChar)0x0061)
+#define LOW_B ((UChar)0x0062)
+#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_J ((UChar)0x006a)
+#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 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_K ((UChar)0x004B)
+#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 MINIMUM_SUPPORTED_CALENDAR_FIELD UCAL_MINUTE
+
+#define MAX_E_COUNT 5
+#define MAX_M_COUNT 5
+//#define MAX_INTERVAL_INDEX 4
+#define MAX_POSITIVE_INT 56632;
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/dtitvfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/dtitvfmt.cpp
new file mode 100644
index 00000000000..79f67ab6058
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtitvfmt.cpp
@@ -0,0 +1,1477 @@
+/*******************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVFMT.CPP
+*
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#include "unicode/dtitvfmt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+//TODO: put in compilation
+//#define DTITVFMT_DEBUG 1
+
+#include "cstring.h"
+#include "unicode/msgfmt.h"
+#include "unicode/dtptngen.h"
+#include "unicode/dtitvinf.h"
+#include "unicode/calendar.h"
+#include "dtitv_impl.h"
+
+#ifdef DTITVFMT_DEBUG
+#include <iostream>
+#include "cstring.h"
+#endif
+
+#include "gregoimp.h"
+
+U_NAMESPACE_BEGIN
+
+
+
+#ifdef DTITVFMT_DEBUG
+#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
+#endif
+
+
+static const UChar gDateFormatSkeleton[][11] = {
+//yMMMMEEEEd
+{LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, CAP_E, CAP_E, CAP_E, CAP_E, LOW_D, 0},
+//yMMMMd
+{LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, LOW_D, 0},
+//yMMMd
+{LOW_Y, CAP_M, CAP_M, CAP_M, LOW_D, 0},
+//yMd
+{LOW_Y, CAP_M, LOW_D, 0} };
+
+
+static const char gDateTimePatternsTag[]="DateTimePatterns";
+
+
+// latestFirst:
+static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
+
+// earliestFirst:
+static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
+
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ UErrorCode& status) {
+ return createInstance(skeleton, Locale::getDefault(), status);
+}
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ const Locale& locale,
+ UErrorCode& status) {
+#ifdef DTITVFMT_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ skeleton.extract(0, skeleton.length(), result, "UTF-8");
+ UnicodeString pat;
+ ((SimpleDateFormat*)dtfmt)->toPattern(pat);
+ pat.extract(0, pat.length(), result_1, "UTF-8");
+ sprintf(mesg, "skeleton: %s; pattern: %s\n", result, result_1);
+ PRINTMESG(mesg)
+#endif
+
+ DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
+ return create(locale, dtitvinf, &skeleton, status);
+}
+
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status) {
+ return createInstance(skeleton, Locale::getDefault(), dtitvinf, status);
+}
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ const Locale& locale,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status) {
+ DateIntervalInfo* ptn = dtitvinf.clone();
+ return create(locale, ptn, &skeleton, status);
+}
+
+
+DateIntervalFormat::DateIntervalFormat()
+: fInfo(NULL),
+ fDateFormat(NULL),
+ fFromCalendar(NULL),
+ fToCalendar(NULL),
+ fDtpng(NULL)
+{}
+
+
+DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
+: Format(itvfmt),
+ fInfo(NULL),
+ fDateFormat(NULL),
+ fFromCalendar(NULL),
+ fToCalendar(NULL),
+ fDtpng(NULL) {
+ *this = itvfmt;
+}
+
+
+DateIntervalFormat&
+DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
+ if ( this != &itvfmt ) {
+ delete fDateFormat;
+ delete fInfo;
+ delete fFromCalendar;
+ delete fToCalendar;
+ delete fDtpng;
+ if ( itvfmt.fDateFormat ) {
+ fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
+ } else {
+ fDateFormat = NULL;
+ }
+ if ( itvfmt.fInfo ) {
+ fInfo = itvfmt.fInfo->clone();
+ } else {
+ fInfo = NULL;
+ }
+ if ( itvfmt.fFromCalendar ) {
+ fFromCalendar = itvfmt.fFromCalendar->clone();
+ } else {
+ fFromCalendar = NULL;
+ }
+ if ( itvfmt.fToCalendar ) {
+ fToCalendar = itvfmt.fToCalendar->clone();
+ } else {
+ fToCalendar = NULL;
+ }
+ fSkeleton = itvfmt.fSkeleton;
+ int8_t i;
+ for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
+ fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
+ }
+ if (itvfmt.fDtpng) {
+ fDtpng = itvfmt.fDtpng->clone();
+ }
+ }
+ return *this;
+}
+
+
+DateIntervalFormat::~DateIntervalFormat() {
+ delete fInfo;
+ delete fDateFormat;
+ delete fFromCalendar;
+ delete fToCalendar;
+ delete fDtpng;
+}
+
+
+Format*
+DateIntervalFormat::clone(void) const {
+ return new DateIntervalFormat(*this);
+}
+
+
+UBool
+DateIntervalFormat::operator==(const Format& other) const {
+ if (typeid(*this) == typeid(other)) {
+ const DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
+#ifdef DTITVFMT_DEBUG
+ UBool equal;
+ equal = (this == fmt);
+
+ equal = (*fInfo == *fmt->fInfo);
+ equal = (*fDateFormat == *fmt->fDateFormat);
+ equal = fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) ;
+ equal = fToCalendar->isEquivalentTo(*fmt->fToCalendar) ;
+ equal = (fSkeleton == fmt->fSkeleton);
+#endif
+ UBool res;
+ res = ( this == fmt ) ||
+ ( Format::operator==(other) &&
+ fInfo &&
+ ( *fInfo == *fmt->fInfo ) &&
+ fDateFormat &&
+ ( *fDateFormat == *fmt->fDateFormat ) &&
+ fFromCalendar &&
+ fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) &&
+ fToCalendar &&
+ fToCalendar->isEquivalentTo(*fmt->fToCalendar) &&
+ fSkeleton == fmt->fSkeleton &&
+ fDtpng &&
+ (*fDtpng == *fmt->fDtpng) );
+ int8_t i;
+ for (i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX && res == TRUE; ++i ) {
+ res = ( fIntervalPatterns[i].firstPart ==
+ fmt->fIntervalPatterns[i].firstPart) &&
+ ( fIntervalPatterns[i].secondPart ==
+ fmt->fIntervalPatterns[i].secondPart ) &&
+ ( fIntervalPatterns[i].laterDateFirst ==
+ fmt->fIntervalPatterns[i].laterDateFirst) ;
+ }
+ return res;
+ }
+ return FALSE;
+}
+
+
+
+UnicodeString&
+DateIntervalFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+
+ if ( obj.getType() == Formattable::kObject ) {
+ const UObject* formatObj = obj.getObject();
+ const DateInterval* interval = dynamic_cast<const DateInterval*>(formatObj);
+ if (interval != NULL){
+ return format(interval, appendTo, fieldPosition, status);
+ }
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+}
+
+
+UnicodeString&
+DateIntervalFormat::format(const DateInterval* dtInterval,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+
+ if ( fFromCalendar != NULL && fToCalendar != NULL &&
+ fDateFormat != NULL && fInfo != NULL ) {
+ fFromCalendar->setTime(dtInterval->getFromDate(), status);
+ fToCalendar->setTime(dtInterval->getToDate(), status);
+ if ( U_SUCCESS(status) ) {
+ return format(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
+ }
+ }
+ return appendTo;
+}
+
+
+UnicodeString&
+DateIntervalFormat::format(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+
+ // not support different calendar types and time zones
+ //if ( fromCalendar.getType() != toCalendar.getType() ) {
+ if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ // First, find the largest different calendar field.
+ UCalendarDateFields field = UCAL_FIELD_COUNT;
+
+ if ( fromCalendar.get(UCAL_ERA,status) != toCalendar.get(UCAL_ERA,status)) {
+ field = UCAL_ERA;
+ } else if ( fromCalendar.get(UCAL_YEAR, status) !=
+ toCalendar.get(UCAL_YEAR, status) ) {
+ field = UCAL_YEAR;
+ } else if ( fromCalendar.get(UCAL_MONTH, status) !=
+ toCalendar.get(UCAL_MONTH, status) ) {
+ field = UCAL_MONTH;
+ } else if ( fromCalendar.get(UCAL_DATE, status) !=
+ toCalendar.get(UCAL_DATE, status) ) {
+ field = UCAL_DATE;
+ } else if ( fromCalendar.get(UCAL_AM_PM, status) !=
+ toCalendar.get(UCAL_AM_PM, status) ) {
+ field = UCAL_AM_PM;
+ } else if ( fromCalendar.get(UCAL_HOUR, status) !=
+ toCalendar.get(UCAL_HOUR, status) ) {
+ field = UCAL_HOUR;
+ } else if ( fromCalendar.get(UCAL_MINUTE, status) !=
+ toCalendar.get(UCAL_MINUTE, status) ) {
+ field = UCAL_MINUTE;
+ }
+
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+ if ( field == UCAL_FIELD_COUNT ) {
+ /* ignore the second/millisecond etc. small fields' difference.
+ * use single date when all the above are the same.
+ */
+ return fDateFormat->format(fromCalendar, appendTo, pos);
+ }
+
+ // following call should not set wrong status,
+ // all the pass-in fields are valid till here
+ int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
+ status);
+ const PatternInfo& intervalPattern = fIntervalPatterns[itvPtnIndex];
+
+ if ( intervalPattern.firstPart.isEmpty() &&
+ intervalPattern.secondPart.isEmpty() ) {
+ if ( fDateFormat->isFieldUnitIgnored(field) ) {
+ /* the largest different calendar field is small than
+ * the smallest calendar field in pattern,
+ * return single date format.
+ */
+ return fDateFormat->format(fromCalendar, appendTo, pos);
+ }
+ return fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
+ }
+ // If the first part in interval pattern is empty,
+ // the 2nd part of it saves the full-pattern used in fall-back.
+ // For a 'real' interval pattern, the first part will never be empty.
+ if ( intervalPattern.firstPart.isEmpty() ) {
+ // fall back
+ UnicodeString originalPattern;
+ fDateFormat->toPattern(originalPattern);
+ fDateFormat->applyPattern(intervalPattern.secondPart);
+ appendTo = fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
+ fDateFormat->applyPattern(originalPattern);
+ return appendTo;
+ }
+ Calendar* firstCal;
+ Calendar* secondCal;
+ if ( intervalPattern.laterDateFirst ) {
+ firstCal = &toCalendar;
+ secondCal = &fromCalendar;
+ } else {
+ firstCal = &fromCalendar;
+ secondCal = &toCalendar;
+ }
+ // break the interval pattern into 2 parts,
+ // first part should not be empty,
+ UnicodeString originalPattern;
+ fDateFormat->toPattern(originalPattern);
+ fDateFormat->applyPattern(intervalPattern.firstPart);
+ fDateFormat->format(*firstCal, appendTo, pos);
+ if ( !intervalPattern.secondPart.isEmpty() ) {
+ fDateFormat->applyPattern(intervalPattern.secondPart);
+ fDateFormat->format(*secondCal, appendTo, pos);
+ }
+ fDateFormat->applyPattern(originalPattern);
+ return appendTo;
+}
+
+
+
+void
+DateIntervalFormat::parseObject(const UnicodeString& /* source */,
+ Formattable& /* result */,
+ ParsePosition& /* parse_pos */) const {
+ // parseObject(const UnicodeString&, Formattable&, UErrorCode&) const
+ // will set status as U_INVALID_FORMAT_ERROR if
+ // parse_pos is still 0
+}
+
+
+
+
+const DateIntervalInfo*
+DateIntervalFormat::getDateIntervalInfo() const {
+ return fInfo;
+}
+
+
+void
+DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
+ UErrorCode& status) {
+ delete fInfo;
+ fInfo = new DateIntervalInfo(newItvPattern);
+ if ( fDateFormat ) {
+ initializePattern(status);
+ }
+}
+
+
+
+const DateFormat*
+DateIntervalFormat::getDateFormat() const {
+ return fDateFormat;
+}
+
+
+void
+DateIntervalFormat::adoptTimeZone(TimeZone* zone)
+{
+ if (fDateFormat != NULL) {
+ fDateFormat->adoptTimeZone(zone);
+ }
+ // The fDateFormat has the master calendar for the DateIntervalFormat and has
+ // ownership of any adopted TimeZone; fFromCalendar and fToCalendar are internal
+ // work clones of that calendar (and should not also be given ownership of the
+ // adopted TimeZone).
+ if (fFromCalendar) {
+ fFromCalendar->setTimeZone(*zone);
+ }
+ if (fToCalendar) {
+ fToCalendar->setTimeZone(*zone);
+ }
+}
+
+void
+DateIntervalFormat::setTimeZone(const TimeZone& zone)
+{
+ if (fDateFormat != NULL) {
+ fDateFormat->setTimeZone(zone);
+ }
+ // The fDateFormat has the master calendar for the DateIntervalFormat;
+ // fFromCalendar and fToCalendar are internal work clones of that calendar.
+ if (fFromCalendar) {
+ fFromCalendar->setTimeZone(zone);
+ }
+ if (fToCalendar) {
+ fToCalendar->setTimeZone(zone);
+ }
+}
+
+const TimeZone&
+DateIntervalFormat::getTimeZone() const
+{
+ if (fDateFormat != NULL) {
+ return fDateFormat->getTimeZone();
+ }
+ // If fDateFormat is NULL (unexpected), create default timezone.
+ return *(TimeZone::createDefault());
+}
+
+DateIntervalFormat::DateIntervalFormat(const Locale& locale,
+ DateIntervalInfo* dtItvInfo,
+ const UnicodeString* skeleton,
+ UErrorCode& status)
+: fInfo(NULL),
+ fDateFormat(NULL),
+ fFromCalendar(NULL),
+ fToCalendar(NULL),
+ fDtpng(NULL)
+{
+ if ( U_FAILURE(status) ) {
+ delete dtItvInfo;
+ return;
+ }
+ fDtpng = DateTimePatternGenerator::createInstance(locale, status);
+ SimpleDateFormat* dtfmt = createSDFPatternInstance(*skeleton, locale,
+ fDtpng, status);
+ if ( U_FAILURE(status) ) {
+ delete dtItvInfo;
+ delete fDtpng;
+ delete dtfmt;
+ return;
+ }
+ if ( dtfmt == NULL || dtItvInfo == NULL || fDtpng == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ // safe to delete NULL
+ delete dtfmt;
+ delete dtItvInfo;
+ delete fDtpng;
+ return;
+ }
+ if ( skeleton ) {
+ fSkeleton = *skeleton;
+ }
+ fInfo = dtItvInfo;
+ fDateFormat = dtfmt;
+ if ( dtfmt->getCalendar() ) {
+ fFromCalendar = dtfmt->getCalendar()->clone();
+ fToCalendar = dtfmt->getCalendar()->clone();
+ } else {
+ fFromCalendar = NULL;
+ fToCalendar = NULL;
+ }
+ initializePattern(status);
+}
+
+
+SimpleDateFormat* U_EXPORT2
+DateIntervalFormat::createSDFPatternInstance(const UnicodeString& skeleton,
+ const Locale& locale,
+ DateTimePatternGenerator* dtpng,
+ UErrorCode& status)
+{
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+
+ const UnicodeString pattern = dtpng->getBestPattern(skeleton, status);
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ SimpleDateFormat* dtfmt = new SimpleDateFormat(pattern, locale, status);
+ if ( U_FAILURE(status) ) {
+ delete dtfmt;
+ return NULL;
+ }
+ return dtfmt;
+}
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::create(const Locale& locale,
+ DateIntervalInfo* dtitvinf,
+ const UnicodeString* skeleton,
+ UErrorCode& status) {
+ DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf,
+ skeleton, status);
+ if ( f == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete dtitvinf;
+ } else if ( U_FAILURE(status) ) {
+ // safe to delete f, although nothing acutally is saved
+ delete f;
+ f = 0;
+ }
+ return f;
+}
+
+
+
+/**
+ * Initialize interval patterns locale to this formatter
+ *
+ * This code is a bit complicated since
+ * 1. the interval patterns saved in resource bundle files are interval
+ * patterns based on date or time only.
+ * It does not have interval patterns based on both date and time.
+ * Interval patterns on both date and time are algorithm generated.
+ *
+ * For example, it has interval patterns on skeleton "dMy" and "hm",
+ * but it does not have interval patterns on skeleton "dMyhm".
+ *
+ * The rule to genearte interval patterns for both date and time skeleton are
+ * 1) when the year, month, or day differs, concatenate the two original
+ * expressions with a separator between,
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 11, 2007 10:10am" is
+ * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
+ *
+ * 2) otherwise, present the date followed by the range expression
+ * for the time.
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 10, 2007 11:10am" is
+ * "Jan 10, 2007 10:10 am - 11:10am"
+ *
+ * 2. even a pattern does not request a certion calendar field,
+ * the interval pattern needs to include such field if such fields are
+ * different between 2 dates.
+ * For example, a pattern/skeleton is "hm", but the interval pattern
+ * includes year, month, and date when year, month, and date differs.
+ *
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+void
+DateIntervalFormat::initializePattern(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ const Locale& locale = fDateFormat->getSmpFmtLocale();
+ if ( fSkeleton.isEmpty() ) {
+ UnicodeString fullPattern;
+ fDateFormat->toPattern(fullPattern);
+#ifdef DTITVFMT_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
+ sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+ // fSkeleton is already set by createDateIntervalInstance()
+ // or by createInstance(UnicodeString skeleton, .... )
+ fSkeleton = fDtpng->getSkeleton(fullPattern, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+
+ // initialize the fIntervalPattern ordering
+ int8_t i;
+ for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
+ fIntervalPatterns[i].laterDateFirst = fInfo->getDefaultOrder();
+ }
+
+ /* Check whether the skeleton is a combination of date and time.
+ * For the complication reason 1 explained above.
+ */
+ UnicodeString dateSkeleton;
+ UnicodeString timeSkeleton;
+ UnicodeString normalizedTimeSkeleton;
+ UnicodeString normalizedDateSkeleton;
+
+
+ /* the difference between time skeleton and normalizedTimeSkeleton are:
+ * 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true)
+ * 2. 'a' is omitted in normalized time skeleton.
+ * 3. there is only one appearance for 'h' or 'H', 'm','v', 'z' in normalized
+ * time skeleton
+ *
+ * The difference between date skeleton and normalizedDateSkeleton are:
+ * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
+ * 2. 'E' and 'EE' are normalized into 'EEE'
+ * 3. 'MM' is normalized into 'M'
+ */
+ getDateTimeSkeleton(fSkeleton, dateSkeleton, normalizedDateSkeleton,
+ timeSkeleton, normalizedTimeSkeleton);
+
+#ifdef DTITVFMT_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
+ sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+
+
+ UBool found = setSeparateDateTimePtn(normalizedDateSkeleton,
+ normalizedTimeSkeleton);
+
+ if ( found == false ) {
+ // use fallback
+ // TODO: if user asks "m"(minute), but "d"(day) differ
+ if ( timeSkeleton.length() != 0 ) {
+ if ( dateSkeleton.length() == 0 ) {
+ // prefix with yMd
+ timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
+ UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ // for fall back interval patterns,
+ // the first part of the pattern is empty,
+ // the second part of the pattern is the full-pattern
+ // should be used in fall-back.
+ setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
+ } else {
+ // TODO: fall back
+ }
+ } else {
+ // TODO: fall back
+ }
+ return;
+ } // end of skeleton not found
+ // interval patterns for skeleton are found in resource
+ if ( timeSkeleton.length() == 0 ) {
+ // done
+ } else if ( dateSkeleton.length() == 0 ) {
+ // prefix with yMd
+ timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
+ UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ // for fall back interval patterns,
+ // the first part of the pattern is empty,
+ // the second part of the pattern is the full-pattern
+ // should be used in fall-back.
+ setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
+ } else {
+ /* if both present,
+ * 1) when the year, month, or day differs,
+ * concatenate the two original expressions with a separator between,
+ * 2) otherwise, present the date followed by the
+ * range expression for the time.
+ */
+ /*
+ * 1) when the year, month, or day differs,
+ * concatenate the two original expressions with a separator between,
+ */
+ // if field exists, use fall back
+ UnicodeString skeleton = fSkeleton;
+ if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) {
+ // prefix skeleton with 'd'
+ skeleton.insert(0, LOW_D);
+ setFallbackPattern(UCAL_DATE, skeleton, status);
+ }
+ if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) {
+ // then prefix skeleton with 'M'
+ skeleton.insert(0, CAP_M);
+ setFallbackPattern(UCAL_MONTH, skeleton, status);
+ }
+ if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) {
+ // then prefix skeleton with 'y'
+ skeleton.insert(0, LOW_Y);
+ setFallbackPattern(UCAL_YEAR, skeleton, status);
+ }
+
+ /*
+ * 2) otherwise, present the date followed by the
+ * range expression for the time.
+ */
+ // Need the Date/Time pattern for concatnation the date with
+ // the time interval.
+ // The date/time pattern ( such as {0} {1} ) is saved in
+ // calendar, that is why need to get the CalendarData here.
+ CalendarData* calData = new CalendarData(locale, NULL, status);
+
+ if ( U_FAILURE(status) ) {
+ delete calData;
+ return;
+ }
+
+ if ( calData == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ const UResourceBundle* dateTimePatternsRes = calData->getByKey(
+ gDateTimePatternsTag, status);
+ int32_t dateTimeFormatLength;
+ const UChar* dateTimeFormat = ures_getStringByIndex(
+ dateTimePatternsRes,
+ (int32_t)DateFormat::kDateTime,
+ &dateTimeFormatLength, &status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+
+ UnicodeString datePattern = fDtpng->getBestPattern(dateSkeleton, status);
+
+ concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
+ datePattern, UCAL_AM_PM, status);
+ concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
+ datePattern, UCAL_HOUR, status);
+ concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
+ datePattern, UCAL_MINUTE, status);
+ delete calData;
+ }
+}
+
+
+
+void U_EXPORT2
+DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
+ UnicodeString& dateSkeleton,
+ UnicodeString& normalizedDateSkeleton,
+ UnicodeString& timeSkeleton,
+ UnicodeString& normalizedTimeSkeleton) {
+ // dateSkeleton follows the sequence of y*M*E*d*
+ // timeSkeleton follows the sequence of hm*[v|z]?
+ int32_t ECount = 0;
+ int32_t dCount = 0;
+ int32_t MCount = 0;
+ int32_t yCount = 0;
+ int32_t hCount = 0;
+ int32_t HCount = 0;
+ int32_t mCount = 0;
+ int32_t vCount = 0;
+ int32_t zCount = 0;
+ int32_t i;
+
+ for (i = 0; i < skeleton.length(); ++i) {
+ UChar ch = skeleton[i];
+ switch ( ch ) {
+ case CAP_E:
+ dateSkeleton.append(ch);
+ ++ECount;
+ break;
+ case LOW_D:
+ dateSkeleton.append(ch);
+ ++dCount;
+ break;
+ case CAP_M:
+ dateSkeleton.append(ch);
+ ++MCount;
+ break;
+ case LOW_Y:
+ dateSkeleton.append(ch);
+ ++yCount;
+ break;
+ case CAP_G:
+ case CAP_Y:
+ case LOW_U:
+ case CAP_Q:
+ case LOW_Q:
+ case CAP_L:
+ case LOW_L:
+ case CAP_W:
+ case LOW_W:
+ case CAP_D:
+ case CAP_F:
+ case LOW_G:
+ case LOW_E:
+ case LOW_C:
+ normalizedDateSkeleton.append(ch);
+ dateSkeleton.append(ch);
+ break;
+ case LOW_A:
+ // 'a' is implicitly handled
+ timeSkeleton.append(ch);
+ break;
+ case LOW_H:
+ timeSkeleton.append(ch);
+ ++hCount;
+ break;
+ case CAP_H:
+ timeSkeleton.append(ch);
+ ++HCount;
+ break;
+ case LOW_M:
+ timeSkeleton.append(ch);
+ ++mCount;
+ break;
+ case LOW_Z:
+ ++zCount;
+ timeSkeleton.append(ch);
+ break;
+ case LOW_V:
+ ++vCount;
+ timeSkeleton.append(ch);
+ break;
+ case CAP_V:
+ case CAP_Z:
+ case LOW_K:
+ case CAP_K:
+ case LOW_J:
+ case LOW_S:
+ case CAP_S:
+ case CAP_A:
+ timeSkeleton.append(ch);
+ normalizedTimeSkeleton.append(ch);
+ break;
+ }
+ }
+
+ /* generate normalized form for date*/
+ if ( yCount != 0 ) {
+ normalizedDateSkeleton.append(LOW_Y);
+ }
+ if ( MCount != 0 ) {
+ if ( MCount < 3 ) {
+ normalizedDateSkeleton.append(CAP_M);
+ } else {
+ int32_t i;
+ for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) {
+ normalizedDateSkeleton.append(CAP_M);
+ }
+ }
+ }
+ if ( ECount != 0 ) {
+ if ( ECount <= 3 ) {
+ normalizedDateSkeleton.append(CAP_E);
+ } else {
+ int32_t i;
+ for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) {
+ normalizedDateSkeleton.append(CAP_E);
+ }
+ }
+ }
+ if ( dCount != 0 ) {
+ normalizedDateSkeleton.append(LOW_D);
+ }
+
+ /* generate normalized form for time */
+ if ( HCount != 0 ) {
+ normalizedTimeSkeleton.append(CAP_H);
+ }
+ else if ( hCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_H);
+ }
+ if ( mCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_M);
+ }
+ if ( zCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_Z);
+ }
+ if ( vCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_V);
+ }
+}
+
+
+/**
+ * Generate date or time interval pattern from resource,
+ * and set them into the interval pattern locale to this formatter.
+ *
+ * It needs to handle the following:
+ * 1. need to adjust field width.
+ * For example, the interval patterns saved in DateIntervalInfo
+ * includes "dMMMy", but not "dMMMMy".
+ * Need to get interval patterns for dMMMMy from dMMMy.
+ * Another example, the interval patterns saved in DateIntervalInfo
+ * includes "hmv", but not "hmz".
+ * Need to get interval patterns for "hmz' from 'hmv'
+ *
+ * 2. there might be no pattern for 'y' differ for skeleton "Md",
+ * in order to get interval patterns for 'y' differ,
+ * need to look for it from skeleton 'yMd'
+ *
+ * @param dateSkeleton normalized date skeleton
+ * @param timeSkeleton normalized time skeleton
+ * @return whether the resource is found for the skeleton.
+ * TRUE if interval pattern found for the skeleton,
+ * FALSE otherwise.
+ * @stable ICU 4.0
+ */
+UBool
+DateIntervalFormat::setSeparateDateTimePtn(
+ const UnicodeString& dateSkeleton,
+ const UnicodeString& timeSkeleton) {
+ const UnicodeString* skeleton;
+ // if both date and time skeleton present,
+ // the final interval pattern might include time interval patterns
+ // ( when, am_pm, hour, minute differ ),
+ // but not date interval patterns ( when year, month, day differ ).
+ // For year/month/day differ, it falls back to fall-back pattern.
+ if ( timeSkeleton.length() != 0 ) {
+ skeleton = &timeSkeleton;
+ } else {
+ skeleton = &dateSkeleton;
+ }
+
+ /* interval patterns for skeleton "dMMMy" (but not "dMMMMy")
+ * are defined in resource,
+ * interval patterns for skeleton "dMMMMy" are calculated by
+ * 1. get the best match skeleton for "dMMMMy", which is "dMMMy"
+ * 2. get the interval patterns for "dMMMy",
+ * 3. extend "MMM" to "MMMM" in above interval patterns for "dMMMMy"
+ * getBestSkeleton() is step 1.
+ */
+ // best skeleton, and the difference information
+ int8_t differenceInfo = 0;
+ const UnicodeString* bestSkeleton = fInfo->getBestSkeleton(*skeleton,
+ differenceInfo);
+ /* best skeleton could be NULL.
+ For example: in "ca" resource file,
+ interval format is defined as following
+ intervalFormats{
+ fallback{"{0} - {1}"}
+ }
+ there is no skeletons/interval patterns defined,
+ and the best skeleton match could be NULL
+ */
+ if ( bestSkeleton == NULL ) {
+ return false;
+ }
+
+ // difference:
+ // 0 means the best matched skeleton is the same as input skeleton
+ // 1 means the fields are the same, but field width are different
+ // 2 means the only difference between fields are v/z,
+ // -1 means there are other fields difference
+ if ( differenceInfo == -1 ) {
+ // skeleton has different fields, not only v/z difference
+ return false;
+ }
+
+ if ( timeSkeleton.length() == 0 ) {
+ UnicodeString extendedSkeleton;
+ UnicodeString extendedBestSkeleton;
+ // only has date skeleton
+ setIntervalPattern(UCAL_DATE, skeleton, bestSkeleton, differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+
+ UBool extended = setIntervalPattern(UCAL_MONTH, skeleton, bestSkeleton,
+ differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+
+ if ( extended ) {
+ bestSkeleton = &extendedBestSkeleton;
+ skeleton = &extendedSkeleton;
+ }
+ setIntervalPattern(UCAL_YEAR, skeleton, bestSkeleton, differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+ } else {
+ setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo);
+ setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo);
+ setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo);
+ }
+ return true;
+}
+
+
+
+void
+DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
+ const UnicodeString& skeleton,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ UnicodeString pattern = fDtpng->getBestPattern(skeleton, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ setPatternInfo(field, NULL, &pattern, fInfo->getDefaultOrder());
+}
+
+
+
+
+void
+DateIntervalFormat::setPatternInfo(UCalendarDateFields field,
+ const UnicodeString* firstPart,
+ const UnicodeString* secondPart,
+ UBool laterDateFirst) {
+ // for fall back interval patterns,
+ // the first part of the pattern is empty,
+ // the second part of the pattern is the full-pattern
+ // should be used in fall-back.
+ UErrorCode status = U_ZERO_ERROR;
+ // following should not set any wrong status.
+ int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
+ status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ PatternInfo& ptn = fIntervalPatterns[itvPtnIndex];
+ if ( firstPart ) {
+ ptn.firstPart = *firstPart;
+ }
+ if ( secondPart ) {
+ ptn.secondPart = *secondPart;
+ }
+ ptn.laterDateFirst = laterDateFirst;
+}
+
+void
+DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern) {
+ UBool order = fInfo->getDefaultOrder();
+ setIntervalPattern(field, intervalPattern, order);
+}
+
+
+void
+DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern,
+ UBool laterDateFirst) {
+ const UnicodeString* pattern = &intervalPattern;
+ UBool order = laterDateFirst;
+ // check for "latestFirst:" or "earliestFirst:" prefix
+ int8_t prefixLength = sizeof(gLaterFirstPrefix)/sizeof(gLaterFirstPrefix[0]);
+ int8_t earliestFirstLength = sizeof(gEarlierFirstPrefix)/sizeof(gEarlierFirstPrefix[0]);
+ UnicodeString realPattern;
+ if ( intervalPattern.startsWith(gLaterFirstPrefix, prefixLength) ) {
+ order = true;
+ intervalPattern.extract(prefixLength,
+ intervalPattern.length() - prefixLength,
+ realPattern);
+ pattern = &realPattern;
+ } else if ( intervalPattern.startsWith(gEarlierFirstPrefix,
+ earliestFirstLength) ) {
+ order = false;
+ intervalPattern.extract(earliestFirstLength,
+ intervalPattern.length() - earliestFirstLength,
+ realPattern);
+ pattern = &realPattern;
+ }
+
+ int32_t splitPoint = splitPatternInto2Part(*pattern);
+
+ UnicodeString firstPart;
+ UnicodeString secondPart;
+ pattern->extract(0, splitPoint, firstPart);
+ if ( splitPoint < pattern->length() ) {
+ pattern->extract(splitPoint, pattern->length()-splitPoint, secondPart);
+ }
+ setPatternInfo(field, &firstPart, &secondPart, order);
+}
+
+
+
+
+/**
+ * Generate interval pattern from existing resource
+ *
+ * It not only save the interval patterns,
+ * but also return the extended skeleton and its best match skeleton.
+ *
+ * @param field largest different calendar field
+ * @param skeleton skeleton
+ * @param bestSkeleton the best match skeleton which has interval pattern
+ * defined in resource
+ * @param differenceInfo the difference between skeleton and best skeleton
+ * 0 means the best matched skeleton is the same as input skeleton
+ * 1 means the fields are the same, but field width are different
+ * 2 means the only difference between fields are v/z,
+ * -1 means there are other fields difference
+ *
+ * @param extendedSkeleton extended skeleton
+ * @param extendedBestSkeleton extended best match skeleton
+ * @return whether the interval pattern is found
+ * through extending skeleton or not.
+ * TRUE if interval pattern is found by
+ * extending skeleton, FALSE otherwise.
+ * @stable ICU 4.0
+ */
+UBool
+DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString* skeleton,
+ const UnicodeString* bestSkeleton,
+ int8_t differenceInfo,
+ UnicodeString* extendedSkeleton,
+ UnicodeString* extendedBestSkeleton) {
+ UErrorCode status = U_ZERO_ERROR;
+ // following getIntervalPattern() should not generate error status
+ UnicodeString pattern;
+ fInfo->getIntervalPattern(*bestSkeleton, field, pattern, status);
+ if ( pattern.isEmpty() ) {
+ // single date
+ if ( SimpleDateFormat::isFieldUnitIgnored(*bestSkeleton, field) ) {
+ // do nothing, format will handle it
+ return false;
+ }
+
+ // for 24 hour system, interval patterns in resource file
+ // might not include pattern when am_pm differ,
+ // which should be the same as hour differ.
+ // add it here for simplicity
+ if ( field == UCAL_AM_PM ) {
+ fInfo->getIntervalPattern(*bestSkeleton, UCAL_HOUR, pattern,status);
+ if ( !pattern.isEmpty() ) {
+ setIntervalPattern(field, pattern);
+ }
+ return false;
+ }
+ // else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
+ // first, get best match pattern "MMMd",
+ // since there is no pattern for 'y' differs for skeleton 'MMMd',
+ // need to look for it from skeleton 'yMMMd',
+ // if found, adjust field width in interval pattern from
+ // "MMM" to "MMMM".
+ UChar fieldLetter = fgCalendarFieldToPatternLetter[field];
+ if ( extendedSkeleton ) {
+ *extendedSkeleton = *skeleton;
+ *extendedBestSkeleton = *bestSkeleton;
+ extendedSkeleton->insert(0, fieldLetter);
+ extendedBestSkeleton->insert(0, fieldLetter);
+ // for example, looking for patterns when 'y' differ for
+ // skeleton "MMMM".
+ fInfo->getIntervalPattern(*extendedBestSkeleton,field,pattern,status);
+ if ( pattern.isEmpty() && differenceInfo == 0 ) {
+ // if there is no skeleton "yMMMM" defined,
+ // look for the best match skeleton, for example: "yMMM"
+ const UnicodeString* tmpBest = fInfo->getBestSkeleton(
+ *extendedBestSkeleton, differenceInfo);
+ if ( tmpBest != 0 && differenceInfo != -1 ) {
+ fInfo->getIntervalPattern(*tmpBest, field, pattern, status);
+ bestSkeleton = tmpBest;
+ }
+ }
+ }
+ }
+ if ( !pattern.isEmpty() ) {
+ if ( differenceInfo != 0 ) {
+ UnicodeString adjustIntervalPattern;
+ adjustFieldWidth(*skeleton, *bestSkeleton, pattern, differenceInfo,
+ adjustIntervalPattern);
+ setIntervalPattern(field, adjustIntervalPattern);
+ } else {
+ setIntervalPattern(field, pattern);
+ }
+ if ( extendedSkeleton && !extendedSkeleton->isEmpty() ) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+int32_t U_EXPORT2
+DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern) {
+ UBool inQuote = false;
+ UChar prevCh = 0;
+ int32_t count = 0;
+
+ /* repeatedPattern used to record whether a pattern has already seen.
+ It is a pattern applies to first calendar if it is first time seen,
+ otherwise, it is a pattern applies to the second calendar
+ */
+ UBool patternRepeated[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int8_t PATTERN_CHAR_BASE = 0x41;
+
+ /* loop through the pattern string character by character looking for
+ * the first repeated pattern letter, which breaks the interval pattern
+ * into 2 parts.
+ */
+ int32_t i;
+ UBool foundRepetition = false;
+ for (i = 0; i < intervalPattern.length(); ++i) {
+ UChar ch = intervalPattern.charAt(i);
+
+ if (ch != prevCh && count > 0) {
+ // check the repeativeness of pattern letter
+ UBool repeated = patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)];
+ if ( repeated == FALSE ) {
+ patternRepeated[prevCh - PATTERN_CHAR_BASE] = TRUE;
+ } else {
+ foundRepetition = true;
+ break;
+ }
+ count = 0;
+ }
+ if (ch == '\'') {
+ // Consecutive single quotes are a single quote literal,
+ // either outside of quotes or between quotes
+ if ((i+1) < intervalPattern.length() &&
+ intervalPattern.charAt(i+1) == '\'') {
+ ++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
+ prevCh = ch;
+ ++count;
+ }
+ }
+ // check last pattern char, distinguish
+ // "dd MM" ( no repetition ),
+ // "d-d"(last char repeated ), and
+ // "d-d MM" ( repetition found )
+ if ( count > 0 && foundRepetition == FALSE ) {
+ if ( patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)] == FALSE ) {
+ count = 0;
+ }
+ }
+ return (i - count);
+}
+
+
+
+UnicodeString&
+DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+ // the fall back
+ // no need delete earlierDate and laterDate since they are adopted
+ UnicodeString* earlierDate = new UnicodeString();
+ *earlierDate = fDateFormat->format(fromCalendar, *earlierDate, pos);
+ UnicodeString* laterDate = new UnicodeString();
+ *laterDate = fDateFormat->format(toCalendar, *laterDate, pos);
+ UnicodeString fallbackPattern;
+ fInfo->getFallbackIntervalPattern(fallbackPattern);
+ Formattable fmtArray[2];
+ fmtArray[0].adoptString(earlierDate);
+ fmtArray[1].adoptString(laterDate);
+
+ UnicodeString fallback;
+ MessageFormat::format(fallbackPattern, fmtArray, 2, fallback, status);
+ if ( U_SUCCESS(status) ) {
+ appendTo.append(fallback);
+ }
+ return appendTo;
+}
+
+
+
+
+UBool U_EXPORT2
+DateIntervalFormat::fieldExistsInSkeleton(UCalendarDateFields field,
+ const UnicodeString& skeleton)
+{
+ const UChar fieldChar = fgCalendarFieldToPatternLetter[field];
+ return ( (skeleton.indexOf(fieldChar) == -1)?FALSE:TRUE ) ;
+}
+
+
+
+void U_EXPORT2
+DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
+ const UnicodeString& bestMatchSkeleton,
+ const UnicodeString& bestIntervalPattern,
+ int8_t differenceInfo,
+ UnicodeString& adjustedPtn) {
+ adjustedPtn = bestIntervalPattern;
+ int32_t inputSkeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int32_t bestMatchSkeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
+ DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
+ if ( differenceInfo == 2 ) {
+ adjustedPtn.findAndReplace(UnicodeString((UChar)0x76 /* v */),
+ UnicodeString((UChar)0x7a /* z */));
+ }
+
+ UBool inQuote = false;
+ UChar prevCh = 0;
+ int32_t count = 0;
+
+ const int8_t PATTERN_CHAR_BASE = 0x41;
+
+ // loop through the pattern string character by character
+ int32_t adjustedPtnLength = adjustedPtn.length();
+ int32_t i;
+ for (i = 0; i < adjustedPtnLength; ++i) {
+ UChar ch = adjustedPtn.charAt(i);
+ if (ch != prevCh && count > 0) {
+ // check the repeativeness of pattern letter
+ UChar skeletonChar = prevCh;
+ if ( skeletonChar == CAP_L ) {
+ // there is no "L" (always be "M") in skeleton,
+ // but there is "L" in pattern.
+ // for skeleton "M+", the pattern might be "...L..."
+ skeletonChar = CAP_M;
+ }
+ int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ if ( fieldCount == count && inputFieldCount > fieldCount ) {
+ count = inputFieldCount - fieldCount;
+ int32_t j;
+ for ( j = 0; j < count; ++j ) {
+ adjustedPtn.insert(i, prevCh);
+ }
+ i += count;
+ adjustedPtnLength += count;
+ }
+ count = 0;
+ }
+ if (ch == '\'') {
+ // Consecutive single quotes are a single quote literal,
+ // either outside of quotes or between quotes
+ if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == '\'') {
+ ++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
+ prevCh = ch;
+ ++count;
+ }
+ }
+ if ( count > 0 ) {
+ // last item
+ // check the repeativeness of pattern letter
+ UChar skeletonChar = prevCh;
+ if ( skeletonChar == CAP_L ) {
+ // there is no "L" (always be "M") in skeleton,
+ // but there is "L" in pattern.
+ // for skeleton "M+", the pattern might be "...L..."
+ skeletonChar = CAP_M;
+ }
+ int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ if ( fieldCount == count && inputFieldCount > fieldCount ) {
+ count = inputFieldCount - fieldCount;
+ int32_t j;
+ for ( j = 0; j < count; ++j ) {
+ adjustedPtn.append(prevCh);
+ }
+ }
+ }
+}
+
+
+
+void
+DateIntervalFormat::concatSingleDate2TimeInterval(const UChar* format,
+ int32_t formatLen,
+ const UnicodeString& datePattern,
+ UCalendarDateFields field,
+ UErrorCode& status) {
+ // following should not set wrong status
+ int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
+ status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ PatternInfo& timeItvPtnInfo = fIntervalPatterns[itvPtnIndex];
+ if ( !timeItvPtnInfo.firstPart.isEmpty() ) {
+ // UnicodeString allocated here is adopted, so no need to delete
+ UnicodeString* timeIntervalPattern = new UnicodeString(timeItvPtnInfo.firstPart);
+ timeIntervalPattern->append(timeItvPtnInfo.secondPart);
+ UnicodeString* dateStr = new UnicodeString(datePattern);
+ Formattable fmtArray[2];
+ fmtArray[0].adoptString(timeIntervalPattern);
+ fmtArray[1].adoptString(dateStr);
+ UnicodeString combinedPattern;
+ MessageFormat::format(UnicodeString(TRUE, format, formatLen),
+ fmtArray, 2, combinedPattern, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ setIntervalPattern(field, combinedPattern, timeItvPtnInfo.laterDateFirst);
+ }
+ // else: fall back
+ // it should not happen if the interval format defined is valid
+}
+
+
+
+const UChar
+DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
+{
+ /*GyM*/ CAP_G, LOW_Y, CAP_M,
+ /*wWd*/ LOW_W, CAP_W, LOW_D,
+ /*DEF*/ CAP_D, CAP_E, CAP_F,
+ /*ahH*/ LOW_A, LOW_H, CAP_H,
+ /*m..*/ LOW_M,
+};
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/dtitvinf.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/dtitvinf.cpp
new file mode 100644
index 00000000000..67b9f83323f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtitvinf.cpp
@@ -0,0 +1,650 @@
+/*******************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVINF.CPP
+*
+*******************************************************************************
+*/
+
+#include "unicode/dtitvinf.h"
+
+
+#if !UCONFIG_NO_FORMATTING
+
+//TODO: define it in compiler time
+//#define DTITVINF_DEBUG 1
+
+
+#ifdef DTITVINF_DEBUG
+#include <iostream>
+#endif
+
+#include "cstring.h"
+#include "unicode/msgfmt.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "dtitv_impl.h"
+#include "hash.h"
+#include "gregoimp.h"
+#include "uresimp.h"
+#include "hash.h"
+#include "gregoimp.h"
+#include "uresimp.h"
+
+
+U_NAMESPACE_BEGIN
+
+
+#ifdef DTITVINF_DEBUG
+#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
+
+static const char gCalendarTag[]="calendar";
+static const char gGregorianTag[]="gregorian";
+static const char gIntervalDateTimePatternTag[]="intervalFormats";
+static const char gFallbackPatternTag[]="fallback";
+
+// {0}
+static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
+// {1}
+static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
+
+// default fall-back
+static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
+
+
+
+DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
+: fFallbackIntervalPattern(gDefaultFallbackPattern),
+ fFirstDateInPtnIsLaterDate(false),
+ fIntervalPatterns(NULL)
+{
+ fIntervalPatterns = initHash(status);
+}
+
+
+
+DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
+: fFallbackIntervalPattern(gDefaultFallbackPattern),
+ fFirstDateInPtnIsLaterDate(false),
+ fIntervalPatterns(NULL)
+{
+ initializeData(locale, status);
+}
+
+
+
+void
+DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status) {
+
+ if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
+ setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
+ setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
+ } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
+ lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
+ setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
+ } else {
+ setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
+ }
+}
+
+
+void
+DateIntervalInfo::setFallbackIntervalPattern(
+ const UnicodeString& fallbackPattern,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
+ sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
+ int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
+ sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
+ if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if ( firstPatternIndex > secondPatternIndex ) {
+ fFirstDateInPtnIsLaterDate = true;
+ }
+ fFallbackIntervalPattern = fallbackPattern;
+}
+
+
+
+DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
+: UObject(dtitvinf),
+ fIntervalPatterns(NULL)
+{
+ *this = dtitvinf;
+}
+
+
+
+DateIntervalInfo&
+DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
+ if ( this == &dtitvinf ) {
+ return *this;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ deleteHash(fIntervalPatterns);
+ fIntervalPatterns = initHash(status);
+ copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
+ if ( U_FAILURE(status) ) {
+ return *this;
+ }
+
+ fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
+ fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
+ return *this;
+}
+
+
+DateIntervalInfo*
+DateIntervalInfo::clone() const {
+ return new DateIntervalInfo(*this);
+}
+
+
+DateIntervalInfo::~DateIntervalInfo() {
+ deleteHash(fIntervalPatterns);
+ fIntervalPatterns = NULL;
+}
+
+
+UBool
+DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
+ UBool equal = (
+ fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
+ fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
+
+ if ( equal == TRUE ) {
+ equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
+ }
+
+ return equal;
+}
+
+
+UnicodeString&
+DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields field,
+ UnicodeString& result,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return result;
+ }
+
+ const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
+ if ( patternsOfOneSkeleton != NULL ) {
+ IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
+ if ( U_FAILURE(status) ) {
+ return result;
+ }
+ const UnicodeString& intervalPattern = patternsOfOneSkeleton[index];
+ if ( !intervalPattern.isEmpty() ) {
+ result = intervalPattern;
+ }
+ }
+ return result;
+}
+
+
+UBool
+DateIntervalInfo::getDefaultOrder() const {
+ return fFirstDateInPtnIsLaterDate;
+}
+
+
+UnicodeString&
+DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
+ result = fFallbackIntervalPattern;
+ return result;
+}
+
+#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
+
+void
+DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
+{
+ fIntervalPatterns = initHash(err);
+ if ( U_FAILURE(err) ) {
+ return;
+ }
+ const char *locName = locale.getName();
+ char parentLocale[ULOC_FULLNAME_CAPACITY];
+ int32_t locNameLen;
+ uprv_strcpy(parentLocale, locName);
+ UErrorCode status = U_ZERO_ERROR;
+ Hashtable skeletonSet(FALSE, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+
+ // determine calendar type
+ const char * calendarTypeToUse = gGregorianTag; // initial default
+ char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
+ char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+ // obtain a locale that always has the calendar key value that should be used
+ (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
+ "calendar", "calendar", locName, NULL, FALSE, &status);
+ localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
+ // now get the calendar key value from that locale
+ int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status);
+ if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
+ calendarTypeToUse = calendarType;
+ }
+ status = U_ZERO_ERROR;
+
+ do {
+ UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource;
+ rb = ures_open(NULL, parentLocale, &status);
+ calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status);
+ calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status);
+ itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
+ gIntervalDateTimePatternTag, NULL, &status);
+
+ if ( U_SUCCESS(status) ) {
+ // look for fallback first, since it establishes the default order
+ const UChar* resStr;
+ int32_t resStrLen = 0;
+ resStr = ures_getStringByKeyWithFallback(itvDtPtnResource,
+ gFallbackPatternTag,
+ &resStrLen, &status);
+ if ( U_SUCCESS(status) ) {
+ UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
+ setFallbackIntervalPattern(pattern, status);
+ }
+
+ int32_t size = ures_getSize(itvDtPtnResource);
+ int32_t index;
+ for ( index = 0; index < size; ++index ) {
+ LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index,
+ NULL, &status));
+ if ( U_SUCCESS(status) ) {
+ const char* skeleton = ures_getKey(oneRes.getAlias());
+ if (skeleton == NULL) {
+ continue;
+ }
+ UnicodeString skeletonUniStr(skeleton, -1, US_INV);
+ if ( skeletonSet.geti(skeletonUniStr) == 1 ) {
+ continue;
+ }
+ skeletonSet.puti(skeletonUniStr, 1, status);
+ if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
+ continue; // fallback
+ }
+
+ LocalUResourceBundlePointer intervalPatterns(ures_getByKey(
+ itvDtPtnResource, skeleton, NULL, &status));
+
+ if ( U_FAILURE(status) ) {
+ break;
+ }
+ if ( intervalPatterns == NULL ) {
+ continue;
+ }
+
+ const char* key;
+ int32_t ptnNum = ures_getSize(intervalPatterns.getAlias());
+ int32_t ptnIndex;
+ for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
+ UnicodeString pattern =
+ ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status);
+ if ( U_FAILURE(status) ) {
+ break;
+ }
+
+ UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
+ if ( !uprv_strcmp(key, "y") ) {
+ calendarField = UCAL_YEAR;
+ } else if ( !uprv_strcmp(key, "M") ) {
+ calendarField = UCAL_MONTH;
+ } else if ( !uprv_strcmp(key, "d") ) {
+ calendarField = UCAL_DATE;
+ } else if ( !uprv_strcmp(key, "a") ) {
+ calendarField = UCAL_AM_PM;
+ } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) {
+ calendarField = UCAL_HOUR;
+ } else if ( !uprv_strcmp(key, "m") ) {
+ calendarField = UCAL_MINUTE;
+ }
+ if ( calendarField != UCAL_FIELD_COUNT ) {
+ setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status);
+ }
+ }
+ }
+ }
+ }
+ ures_close(itvDtPtnResource);
+ ures_close(calTypeBundle);
+ ures_close(calBundle);
+ ures_close(rb);
+ status = U_ZERO_ERROR;
+ locNameLen = uloc_getParent(parentLocale, parentLocale,
+ ULOC_FULLNAME_CAPACITY,&status);
+ } while ( locNameLen > 0 );
+}
+
+
+
+void
+DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status) {
+ IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
+ UBool emptyHash = false;
+ if ( patternsOfOneSkeleton == NULL ) {
+ patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
+ emptyHash = true;
+ }
+
+ patternsOfOneSkeleton[index] = intervalPattern;
+ if ( emptyHash == TRUE ) {
+ fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
+ }
+}
+
+
+
+void
+DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
+ int32_t* skeletonFieldWidth) {
+ const int8_t PATTERN_CHAR_BASE = 0x41;
+ int32_t i;
+ for ( i = 0; i < skeleton.length(); ++i ) {
+ // it is an ASCII char in skeleton
+ int8_t ch = (int8_t)skeleton.charAt(i);
+ ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
+ }
+}
+
+
+
+UBool
+DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
+ char patternLetter) {
+ if ( patternLetter == 'M' ) {
+ if ( (fieldWidth <= 2 && anotherFieldWidth > 2) ||
+ (fieldWidth > 2 && anotherFieldWidth <= 2 )) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+const UnicodeString*
+DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
+ int8_t& bestMatchDistanceInfo) const {
+#ifdef DTITVINF_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ skeleton.extract(0, skeleton.length(), result, "UTF-8");
+ sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+
+
+ int32_t inputSkeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int32_t skeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ const int32_t DIFFERENT_FIELD = 0x1000;
+ const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
+ const int32_t BASE = 0x41;
+ const UChar CHAR_V = 0x0076;
+ const UChar CHAR_Z = 0x007A;
+
+ // hack for 'v' and 'z'.
+ // resource bundle only have time skeletons ending with 'v',
+ // but not for time skeletons ending with 'z'.
+ UBool replaceZWithV = false;
+ const UnicodeString* inputSkeleton = &skeleton;
+ UnicodeString copySkeleton;
+ if ( skeleton.indexOf(CHAR_Z) != -1 ) {
+ copySkeleton = skeleton;
+ copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V));
+ inputSkeleton = &copySkeleton;
+ replaceZWithV = true;
+ }
+
+ parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
+ int32_t bestDistance = MAX_POSITIVE_INT;
+ const UnicodeString* bestSkeleton = NULL;
+
+ // 0 means exact the same skeletons;
+ // 1 means having the same field, but with different length,
+ // 2 means only z/v differs
+ // -1 means having different field.
+ bestMatchDistanceInfo = 0;
+ int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
+
+ int32_t pos = -1;
+ const UHashElement* elem = NULL;
+ while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = elem->key;
+ UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
+#ifdef DTITVINF_DEBUG
+ skeleton->extract(0, skeleton->length(), result, "UTF-8");
+ sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+
+ // clear skeleton field width
+ int8_t i;
+ for ( i = 0; i < fieldLength; ++i ) {
+ skeletonFieldWidth[i] = 0;
+ }
+ parseSkeleton(*skeleton, skeletonFieldWidth);
+ // calculate distance
+ int32_t distance = 0;
+ int8_t fieldDifference = 1;
+ for ( i = 0; i < fieldLength; ++i ) {
+ int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
+ int32_t fieldWidth = skeletonFieldWidth[i];
+ if ( inputFieldWidth == fieldWidth ) {
+ continue;
+ }
+ if ( inputFieldWidth == 0 ) {
+ fieldDifference = -1;
+ distance += DIFFERENT_FIELD;
+ } else if ( fieldWidth == 0 ) {
+ fieldDifference = -1;
+ distance += DIFFERENT_FIELD;
+ } else if (stringNumeric(inputFieldWidth, fieldWidth,
+ (char)(i+BASE) ) ) {
+ distance += STRING_NUMERIC_DIFFERENCE;
+ } else {
+ distance += (inputFieldWidth > fieldWidth) ?
+ (inputFieldWidth - fieldWidth) :
+ (fieldWidth - inputFieldWidth);
+ }
+ }
+ if ( distance < bestDistance ) {
+ bestSkeleton = skeleton;
+ bestDistance = distance;
+ bestMatchDistanceInfo = fieldDifference;
+ }
+ if ( distance == 0 ) {
+ bestMatchDistanceInfo = 0;
+ break;
+ }
+ }
+ if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
+ bestMatchDistanceInfo = 2;
+ }
+ return bestSkeleton;
+}
+
+
+
+DateIntervalInfo::IntervalPatternIndex
+DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return kIPI_MAX_INDEX;
+ }
+ IntervalPatternIndex index = kIPI_MAX_INDEX;
+ switch ( field ) {
+ case UCAL_ERA:
+ index = kIPI_ERA;
+ break;
+ case UCAL_YEAR:
+ index = kIPI_YEAR;
+ break;
+ case UCAL_MONTH:
+ index = kIPI_MONTH;
+ break;
+ case UCAL_DATE:
+ case UCAL_DAY_OF_WEEK:
+ //case UCAL_DAY_OF_MONTH:
+ index = kIPI_DATE;
+ break;
+ case UCAL_AM_PM:
+ index = kIPI_AM_PM;
+ break;
+ case UCAL_HOUR:
+ case UCAL_HOUR_OF_DAY:
+ index = kIPI_HOUR;
+ break;
+ case UCAL_MINUTE:
+ index = kIPI_MINUTE;
+ break;
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return index;
+}
+
+
+
+void
+DateIntervalInfo::deleteHash(Hashtable* hTable)
+{
+ if ( hTable == NULL ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = hTable->nextElement(pos)) != NULL ) {
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ delete[] value;
+ }
+ delete fIntervalPatterns;
+}
+
+
+U_CDECL_BEGIN
+
+/**
+ * set hash table value comparator
+ *
+ * @param val1 one value in comparison
+ * @param val2 the other value in comparison
+ * @return TRUE if 2 values are the same, FALSE otherwise
+ */
+static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
+
+static UBool
+U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
+ const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
+ const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
+ UBool ret = TRUE;
+ int8_t i;
+ for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) {
+ ret = (pattern1[i] == pattern2[i]);
+ }
+ return ret;
+}
+
+U_CDECL_END
+
+
+Hashtable*
+DateIntervalInfo::initHash(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(FALSE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if ( U_FAILURE(status) ) {
+ delete hTable;
+ return NULL;
+ }
+ hTable->setValueComparator(dtitvinfHashTableValueComparator);
+ return hTable;
+}
+
+
+void
+DateIntervalInfo::copyHash(const Hashtable* source,
+ Hashtable* target,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
+ int8_t i;
+ for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
+ copy[i] = value[i];
+ }
+ target->put(UnicodeString(*key), copy, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/dtptngen.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/dtptngen.cpp
new file mode 100644
index 00000000000..f848bc3ee23
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtptngen.cpp
@@ -0,0 +1,2156 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, 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/uloc.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.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"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+/**
+ * If we are on EBCDIC, use an iterator which will
+ * traverse the bundles in ASCII order.
+ */
+#define U_USE_ASCII_BUNDLE_ITERATOR
+#define U_SORT_ASCII_BUNDLE_ITERATOR
+#endif
+
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+
+#include "unicode/ustring.h"
+#include "uarrsort.h"
+
+struct UResAEntry {
+ UChar *key;
+ UResourceBundle *item;
+};
+
+struct UResourceBundleAIterator {
+ UResourceBundle *bund;
+ UResAEntry *entries;
+ int32_t num;
+ int32_t cursor;
+};
+
+/* Must be C linkage to pass function pointer to the sort function */
+
+#if !defined (OS390) && !defined (OS400)
+extern "C"
+#endif
+static int32_t U_CALLCONV
+ures_a_codepointSort(const void *context, const void *left, const void *right) {
+ //CompareContext *cmp=(CompareContext *)context;
+ return u_strcmp(((const UResAEntry *)left)->key,
+ ((const UResAEntry *)right)->key);
+}
+
+
+static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ aiter->bund = bund;
+ aiter->num = ures_getSize(aiter->bund);
+ aiter->cursor = 0;
+#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
+ aiter->entries = NULL;
+#else
+ aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num);
+ for(int i=0;i<aiter->num;i++) {
+ aiter->entries[i].item = ures_getByIndex(aiter->bund, i, NULL, status);
+ const char *akey = ures_getKey(aiter->entries[i].item);
+ int32_t len = uprv_strlen(akey)+1;
+ aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar));
+ u_charsToUChars(akey, aiter->entries[i].key, len);
+ }
+ uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, NULL, TRUE, status);
+#endif
+}
+
+static void ures_a_close(UResourceBundleAIterator *aiter) {
+#if defined(U_SORT_ASCII_BUNDLE_ITERATOR)
+ for(int i=0;i<aiter->num;i++) {
+ uprv_free(aiter->entries[i].key);
+ ures_close(aiter->entries[i].item);
+ }
+#endif
+}
+
+static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_t *len, const char **key, UErrorCode *err) {
+#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
+ return ures_getNextString(aiter->bund, len, key, err);
+#else
+ if(U_FAILURE(*err)) return NULL;
+ UResourceBundle *item = aiter->entries[aiter->cursor].item;
+ const UChar* ret = ures_getString(item, len, err);
+ *key = ures_getKey(item);
+ aiter->cursor++;
+ return ret;
+#endif
+}
+
+
+#endif
+
+
+U_NAMESPACE_BEGIN
+
+
+// *****************************************************************************
+// class DateTimePatternGenerator
+// *****************************************************************************
+static const UChar Canonical_Items[] = {
+ // GyQMwWEdDFHmsSv
+ CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_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},
+ {LOW_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
+ {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT + DT_DELTA, 3, 0},
+ {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG + DT_DELTA, 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_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 1},
+ {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2},
+ {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 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_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical
+ {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},
+ {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 don't 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},
+ {CAP_V, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 3},
+ {CAP_V, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
+ {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
+ };
+
+static const char* const CLDR_FIELD_APPEND[] = {
+ "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
+ "Hour", "Minute", "Second", "*", "Timezone"
+};
+
+static const char* const CLDR_FIELD_NAME[] = {
+ "era", "year", "quarter", "month", "week", "*", "weekday", "day", "*", "*", "dayperiod",
+ "hour", "minute", "second", "*", "zone"
+};
+
+static const char* const 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) {
+ DateTimePatternGenerator *result = new DateTimePatternGenerator(locale, status);
+ if (result == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ delete result;
+ result = NULL;
+ }
+ return result;
+}
+
+DateTimePatternGenerator* U_EXPORT2
+DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
+ DateTimePatternGenerator *result = new DateTimePatternGenerator(status);
+ if (result == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ delete result;
+ result = NULL;
+ }
+ return result;
+}
+
+DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) :
+ 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) :
+ 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;
+ }
+ else {
+ initData(locale, status);
+ }
+}
+
+DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) :
+ UObject(),
+ skipMatcher(NULL),
+ fAvailableFormatKeyHash(NULL)
+{
+ fp = new FormatParser();
+ dtMatcher = new DateTimeMatcher();
+ distanceInfo = new DistanceInfo();
+ patternMap = new PatternMap();
+ *this=other;
+}
+
+DateTimePatternGenerator&
+DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
+ pLocale = other.pLocale;
+ fDefaultHourFormatChar = other.fDefaultHourFormatChar;
+ *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();
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ patternMap->copyFrom(*other.patternMap, status);
+ copyHashtable(other.fAvailableFormatKeyHash, status);
+ 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;
+ }
+
+ 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, UErrorCode &status) {
+ //const char *baseLangName = locale.getBaseName(); // unused
+
+ skipMatcher = NULL;
+ fAvailableFormatKeyHash=NULL;
+ addCanonicalItems();
+ addICUPatterns(locale, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ addCLDRData(locale, status);
+ setDateTimeFromCalendar(locale, status);
+ setDecimalSymbols(locale, status);
+} // 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;
+ DateFormat* df;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Load with ICU patterns
+ for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) {
+ DateFormat::EStyle style = (DateFormat::EStyle)i;
+ df = DateFormat::createDateInstance(style, locale);
+ SimpleDateFormat* sdf;
+ if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
+ conflictingStatus = addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status);
+ }
+ // TODO Maybe we should return an error when the date format isn't simple.
+ delete df;
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ df = DateFormat::createTimeInstance(style, locale);
+ if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
+ conflictingStatus = addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status);
+ // HACK for hh:ss
+ if ( i==DateFormat::kMedium ) {
+ hackPattern = dfPattern;
+ }
+ }
+ // TODO Maybe we should return an error when the date format isn't simple.
+ delete df;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+}
+
+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;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
+
+static const UChar hourFormatChars[] = { CAP_H, LOW_H, CAP_K, LOW_K, 0 }; // HhKk, the hour format characters
+
+void
+DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& err) {
+ UResourceBundle *rb, *calTypeBundle, *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.
+
+ err = U_ZERO_ERROR;
+
+ fDefaultHourFormatChar = 0;
+ 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);
+ if (rb == NULL || U_FAILURE(err)) {
+ return;
+ }
+ const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
+ const char * calendarTypeToUse = DT_DateTimeGregorianTag; // initial default
+ char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
+ if ( U_SUCCESS(err) ) {
+ char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+ // obtain a locale that always has the calendar key value that should be used
+ (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
+ "calendar", "calendar", locale.getName(), NULL, FALSE, &err);
+ localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
+ // now get the calendar key value from that locale
+ int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &err);
+ if (U_SUCCESS(err) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
+ calendarTypeToUse = calendarType;
+ }
+ err = U_ZERO_ERROR;
+ }
+ calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err);
+ calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err);
+
+ key=NULL;
+ int32_t dtCount=0;
+ patBundle = ures_getByKeyWithFallback(calTypeBundle, 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);
+ } else if (dtCount==4) { // short time format
+ // set fDefaultHourFormatChar to the hour format character from this pattern
+ int32_t tfIdx, tfLen = rbPattern.length();
+ UBool ignoreChars = FALSE;
+ for (tfIdx = 0; tfIdx < tfLen; tfIdx++) {
+ UChar tfChar = rbPattern.charAt(tfIdx);
+ if ( tfChar == SINGLE_QUOTE ) {
+ ignoreChars = !ignoreChars; // toggle (handle quoted literals & '' for single quote)
+ } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != NULL ) {
+ fDefaultHourFormatChar = tfChar;
+ break;
+ }
+ }
+ }
+ }
+ }
+ ures_close(patBundle);
+
+ err = U_ZERO_ERROR;
+ patBundle = ures_getByKeyWithFallback(calTypeBundle, 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(calTypeBundle, 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(calTypeBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
+ if (U_SUCCESS(err)) {
+ int32_t numberKeys = ures_getSize(patBundle);
+ int32_t len;
+ const UChar *retPattern;
+ key=NULL;
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+ UResourceBundleAIterator aiter;
+ ures_a_open(&aiter, patBundle, &err);
+#endif
+ for(i=0; i<numberKeys; ++i) {
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+ retPattern=ures_a_getNextString(&aiter, &len, &key, &err);
+#else
+ retPattern=ures_getNextString(patBundle, &len, &key, &err);
+#endif
+ UnicodeString format=UnicodeString(retPattern);
+ UnicodeString retKey=UnicodeString(key, -1, US_INV);
+ setAvailableFormat(retKey, err);
+ // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
+ // but not a previous availableFormats entry:
+ conflictingStatus = addPatternWithSkeleton(format, &retKey, TRUE, conflictingPattern, err);
+ }
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+ ures_a_close(&aiter);
+#endif
+ }
+ ures_close(patBundle);
+ ures_close(calTypeBundle);
+ ures_close(calBundle);
+ ures_close(rb);
+
+ err = U_ZERO_ERROR;
+ char parentLocale[50];
+ int32_t localeNameLen=0;
+ uprv_strcpy(parentLocale, curLocaleName);
+ while((localeNameLen=uloc_getParent(parentLocale, parentLocale, 50, &err))>=0 ) {
+ rb = ures_open(NULL, parentLocale, &err);
+ curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
+ uprv_strcpy(parentLocale, curLocaleName);
+ calBundle = ures_getByKey(rb, DT_DateTimeCalendarTag, NULL, &err);
+ calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &err);
+ patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
+ if (U_SUCCESS(err)) {
+ int32_t numberKeys = ures_getSize(patBundle);
+ int32_t len;
+ const UChar *retPattern;
+ key=NULL;
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+ UResourceBundleAIterator aiter;
+ ures_a_open(&aiter, patBundle, &err);
+#endif
+ for(i=0; i<numberKeys; ++i) {
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+ retPattern=ures_a_getNextString(&aiter, &len, &key, &err);
+#else
+ retPattern=ures_getNextString(patBundle, &len, &key, &err);
+#endif
+ UnicodeString format=UnicodeString(retPattern);
+ UnicodeString retKey=UnicodeString(key, -1, US_INV);
+ if ( !isAvailableFormatSet(retKey) ) {
+ setAvailableFormat(retKey, err);
+ // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
+ // but not a previous availableFormats entry:
+ conflictingStatus = addPatternWithSkeleton(format, &retKey, TRUE, conflictingPattern, err);
+ }
+ }
+#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
+ ures_a_close(&aiter);
+#endif
+ }
+ err = U_ZERO_ERROR; // reset; if this locale lacks the necessary data, need to keep checking up to root.
+ ures_close(patBundle);
+ ures_close(calTypeBundle);
+ 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) {
+ return getBestPattern(patternForm, UDATPG_MATCH_NO_OPTIONS, status);
+}
+
+UnicodeString
+DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, 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;
+
+ UnicodeString patternFormCopy = UnicodeString(patternForm);
+ patternFormCopy.findAndReplace(UnicodeString(LOW_J), UnicodeString(fDefaultHourFormatChar));
+
+ resultPattern.remove();
+ dtMatcher->set(patternFormCopy, fp);
+ const PtnSkeleton* specifiedSkeleton=NULL;
+ bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton);
+ if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
+ resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, FALSE, options);
+
+ return resultPattern;
+ }
+ int32_t neededFields = dtMatcher->getFieldMask();
+ UnicodeString datePattern=getBestAppending(neededFields & dateMask, options);
+ UnicodeString timePattern=getBestAppending(neededFields & timeMask, options);
+ 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[] = { timePattern, datePattern };
+ resultPattern = MessageFormat::format(dtFormat, dateTimeObject, 2, resultPattern, status );
+ return resultPattern;
+}
+
+UnicodeString
+DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
+ const UnicodeString& skeleton,
+ UErrorCode& status) {
+ return replaceFieldTypes(pattern, skeleton, UDATPG_MATCH_NO_OPTIONS, status);
+}
+
+UnicodeString
+DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
+ const UnicodeString& skeleton,
+ UDateTimePatternMatchOptions options,
+ UErrorCode& /*status*/) {
+ dtMatcher->set(skeleton, fp);
+ UnicodeString result = adjustFieldTypes(pattern, NULL, FALSE, options);
+ 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)
+{
+ return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status);
+}
+
+// For DateTimePatternGenerator::addPatternWithSkeleton -
+// If skeletonToUse is specified, then an availableFormats entry is being added. In this case:
+// 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.
+// 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified
+// (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override
+// parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual
+// specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was
+// derived (i.e. entries derived from the standard date/time patters for the specified locale).
+// 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a
+// specified skeleton (which sets a new field in the PtnElem in the PatternMap).
+UDateTimePatternConflict
+DateTimePatternGenerator::addPatternWithSkeleton(
+ const UnicodeString& pattern,
+ const UnicodeString* skeletonToUse,
+ UBool override,
+ UnicodeString& conflictingPattern,
+ UErrorCode& status)
+{
+
+ UnicodeString basePattern;
+ PtnSkeleton skeleton;
+ UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
+
+ DateTimeMatcher matcher;
+ if ( skeletonToUse == NULL ) {
+ matcher.set(pattern, fp, skeleton);
+ matcher.getBasePattern(basePattern);
+ } else {
+ matcher.set(*skeletonToUse, fp, skeleton); // this still trims skeleton fields to max len 3, may need to change it.
+ matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse;
+ }
+ UBool entryHadSpecifiedSkeleton;
+ const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton);
+ if (duplicatePattern != NULL ) {
+ conflictingStatus = UDATPG_BASE_CONFLICT;
+ conflictingPattern = *duplicatePattern;
+ if (!override || (skeletonToUse != NULL && entryHadSpecifiedSkeleton)) {
+ return conflictingStatus;
+ }
+ }
+ const PtnSkeleton* entrySpecifiedSkeleton = NULL;
+ duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton);
+ if (duplicatePattern != NULL ) {
+ conflictingStatus = UDATPG_CONFLICT;
+ conflictingPattern = *duplicatePattern;
+ if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) {
+ return conflictingStatus;
+ }
+ }
+ patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, 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,
+ const PtnSkeleton** specifiedSkeletonPtr) {
+ int32_t bestDistance = 0x7fffffff;
+ DistanceInfo tempInfo;
+ const UnicodeString *bestPattern=NULL;
+ const PtnSkeleton* specifiedSkeleton=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(), &specifiedSkeleton);
+ missingFields->setTo(tempInfo);
+ if (distance==0) {
+ break;
+ }
+ }
+ }
+
+ // If the best raw match had a specified skeleton and that skeleton was requested by the caller,
+ // then return it too. This generally happens when the caller needs to pass that skeleton
+ // through to adjustFieldTypes so the latter can do a better job.
+ if (bestPattern && specifiedSkeletonPtr) {
+ *specifiedSkeletonPtr = specifiedSkeleton;
+ }
+ return bestPattern;
+}
+
+UnicodeString
+DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
+ const PtnSkeleton* specifiedSkeleton,
+ UBool fixFractionalSeconds,
+ UDateTimePatternMatchOptions options) {
+ 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) {
+ // Here:
+ // - "reqField" is the field from the originally requested skeleton, with length
+ // "reqFieldLen".
+ // - "field" is the field from the found pattern.
+ //
+ // The adjusted field should consist of characters from the originally requested
+ // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or
+ // UDATPG_WEEKDAY_FIELD, in which case it should consist of characters from the
+ // found pattern.
+ //
+ // The length of the adjusted field (adjFieldLen) should match that in the originally
+ // requested skeleton, except that in the following cases the length of the adjusted field
+ // should match that in the found pattern (i.e. the length of this pattern field should
+ // not be adjusted):
+ // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is
+ // not set (ticket #7180). Note, we may want to implement a similar change for other
+ // numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for
+ // field length, but options bits can be used to override this.
+ // 2. There is a specified skeleton for the found pattern and one of the following is true:
+ // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.
+ // b) The pattern field is numeric and the skeleton field is not, or vice versa.
+
+ UnicodeString reqField = dtMatcher->skeleton.original[typeValue];
+ int32_t reqFieldLen = reqField.length();
+ if (reqField.charAt(0) == CAP_E && reqFieldLen < 3)
+ reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e
+ int32_t adjFieldLen = reqFieldLen;
+ if ( (typeValue==UDATPG_HOUR_FIELD && (options & UDATPG_MATCH_HOUR_FIELD_LENGTH)==0) ||
+ (typeValue==UDATPG_MINUTE_FIELD && (options & UDATPG_MATCH_MINUTE_FIELD_LENGTH)==0) ||
+ (typeValue==UDATPG_SECOND_FIELD && (options & UDATPG_MATCH_SECOND_FIELD_LENGTH)==0) ) {
+ adjFieldLen = field.length();
+ } else if (specifiedSkeleton) {
+ UnicodeString skelField = specifiedSkeleton->original[typeValue];
+ int32_t skelFieldLen = skelField.length();
+ UBool patFieldIsNumeric = (row->type > 0);
+ UBool skelFieldIsNumeric = (specifiedSkeleton->type[typeValue] > 0);
+ if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) {
+ // don't adjust the field length in the found pattern
+ adjFieldLen = field.length();
+ }
+ }
+ UChar c = (typeValue!= UDATPG_HOUR_FIELD && typeValue!= UDATPG_MONTH_FIELD && typeValue!= UDATPG_WEEKDAY_FIELD)?
+ reqField.charAt(0): field.charAt(0);
+ field.remove();
+ for (int32_t i=adjFieldLen; i>0; --i) {
+ field+=c;
+ }
+ }
+ newPattern+=field;
+ }
+ }
+ return newPattern;
+}
+
+UnicodeString
+DateTimePatternGenerator::getBestAppending(int32_t missingFields, UDateTimePatternMatchOptions options) {
+ UnicodeString resultPattern, tempPattern;
+ UErrorCode err=U_ZERO_ERROR;
+ int32_t lastMissingFieldMask=0;
+ if (missingFields!=0) {
+ resultPattern=UnicodeString();
+ const PtnSkeleton* specifiedSkeleton=NULL;
+ tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton);
+ resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, FALSE, options);
+ 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, specifiedSkeleton, TRUE, options);
+ distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK;
+ continue;
+ }
+ int32_t startingMask = distanceInfo->missingFieldMask;
+ tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton);
+ tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, FALSE, options);
+ int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
+ int32_t topField=getTopBitNumber(foundMask);
+ UnicodeString appendName;
+ getAppendName((UDateTimePatternField)topField, appendName);
+ const Formattable formatPattern[] = {
+ resultPattern,
+ tempPattern,
+ appendName
+ };
+ UnicodeString emptyStr;
+ resultPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, emptyStr, err);
+ lastMissingFieldMask = distanceInfo->missingFieldMask;
+ }
+ }
+ return resultPattern;
+}
+
+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, UErrorCode &status) {
+
+ if (other == NULL) {
+ return;
+ }
+ if (fAvailableFormatKeyHash != NULL) {
+ delete fAvailableFormatKeyHash;
+ fAvailableFormatKeyHash = NULL;
+ }
+ initHashtable(status);
+ if(U_FAILURE(status)){
+ 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, status);
+ if(U_FAILURE(status)){
+ 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
+ UBool skeletonWasSpecified,
+ 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);
+ curElem->skeletonWasSpecified = skeletonWasSpecified;
+ }
+ 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);
+ curElem->skeletonWasSpecified = skeletonWasSpecified;
+ }
+ 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, UBool& skeletonWasSpecified) { // key to search for
+ PtnElem *curElem;
+
+ if ((curElem=getHeader(basePattern.charAt(0)))==NULL) {
+ return NULL; // no match
+ }
+
+ do {
+ if ( basePattern.compare(curElem->basePattern)==0 ) {
+ skeletonWasSpecified = curElem->skeletonWasSpecified;
+ return &(curElem->pattern);
+ }
+ curElem=curElem->next;
+ }while (curElem != NULL);
+
+ return NULL;
+} // PatternMap::getFromBasePattern
+
+
+// Find the pattern from the given skeleton.
+// At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),
+// the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)
+// and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the
+// optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
+// for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
+const UnicodeString *
+PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for
+ PtnElem *curElem;
+
+ if (specifiedSkeletonPtr) {
+ *specifiedSkeletonPtr = NULL;
+ }
+
+ // 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;
+ if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
+ for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (curElem->skeleton->original[i].compare(skeleton.original[i]) != 0 )
+ {
+ break;
+ }
+ }
+ } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
+ for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 )
+ {
+ break;
+ }
+ }
+ }
+ if (i == UDATPG_FIELD_COUNT) {
+ if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) {
+ *specifiedSkeletonPtr = curElem->skeleton;
+ }
+ 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] = 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, UBool strict) {
+ int32_t len = s.length();
+ if (len == 0) {
+ return -1;
+ }
+ UChar ch = s.charAt(0);
+
+ // Verify that all are the same character.
+ for (int32_t l = 1; l < len; l++) {
+ if (ch != s.charAt(l)) {
+ return -1;
+ }
+ }
+ int32_t i = 0;
+ int32_t bestRow = -1;
+ while (dtTypes[i].patternChar != '\0') {
+ if ( dtTypes[i].patternChar != ch ) {
+ ++i;
+ continue;
+ }
+ bestRow = i;
+ if (dtTypes[i].patternChar != dtTypes[i+1].patternChar) {
+ return i;
+ }
+ if (dtTypes[i+1].minLen <= len) {
+ ++i;
+ continue;
+ }
+ return i;
+ }
+ return strict ? -1 : bestRow;
+}
+
+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-4.8.1/i18n/dtptngen_impl.h b/Build/source/libs/icu/icu-4.8.1/i18n/dtptngen_impl.h
new file mode 100644
index 00000000000..acc55b18724
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtptngen_impl.h
@@ -0,0 +1,259 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, 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_K ((UChar)0x004B)
+#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_J ((UChar)0x006A)
+#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 -0x102
+#define DT_LONG -0x103
+#define DT_NUMERIC 0x100
+#define DT_NARROW -0x101
+#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;
+ int16_t type;
+ int16_t minLen;
+ int16_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;
+ UBool skeletonWasSpecified; // if specified in availableFormats, not derived
+ 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) { return getCanonicalIndex(s, TRUE); }
+ int32_t getCanonicalIndex(const UnicodeString& s, UBool strict);
+ 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, UBool skeletonWasSpecified, UErrorCode& status);
+ const UnicodeString* getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified);
+ const UnicodeString* getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr = 0);
+ 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 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 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-4.8.1/i18n/dtrule.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/dtrule.cpp
new file mode 100644
index 00000000000..c2eeb052a40
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/dtrule.cpp
@@ -0,0 +1,139 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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) ||
+ (typeid(*this) == typeid(that) &&
+ 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-4.8.1/i18n/esctrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/esctrn.cpp
new file mode 100644
index 00000000000..93f13f5816c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/esctrn.h b/Build/source/libs/icu/icu-4.8.1/i18n/esctrn.h
new file mode 100644
index 00000000000..96872b91684
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/ethpccal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.cpp
new file mode 100644
index 00000000000..9317dead0ae
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.cpp
@@ -0,0 +1,214 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003 - 2009, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "umutex.h"
+#include "ethpccal.h"
+#include "cecal.h"
+#include <float.h>
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicCalendar)
+
+//static const int32_t JD_EPOCH_OFFSET_AMETE_ALEM = -285019;
+static const int32_t JD_EPOCH_OFFSET_AMETE_MIHRET = 1723856;
+static const int32_t AMETE_MIHRET_DELTA = 5500; // 5501 - 1 (Amete Alem 5501 = Amete Mihret 1)
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+EthiopicCalendar::EthiopicCalendar(const Locale& aLocale,
+ UErrorCode& success,
+ EEraType type /*= AMETE_MIHRET_ERA*/)
+: CECalendar(aLocale, success),
+ eraType(type)
+{
+}
+
+EthiopicCalendar::EthiopicCalendar(const EthiopicCalendar& other)
+: CECalendar(other),
+ eraType(other.eraType)
+{
+}
+
+EthiopicCalendar::~EthiopicCalendar()
+{
+}
+
+Calendar*
+EthiopicCalendar::clone() const
+{
+ return new EthiopicCalendar(*this);
+}
+
+const char *
+EthiopicCalendar::getType() const
+{
+ if (isAmeteAlemEra()) {
+ return "ethiopic-amete-alem";
+ }
+ return "ethiopic";
+}
+
+void
+EthiopicCalendar::setAmeteAlemEra(UBool onOff)
+{
+ eraType = onOff ? AMETE_ALEM_ERA : AMETE_MIHRET_ERA;
+}
+
+UBool
+EthiopicCalendar::isAmeteAlemEra() const
+{
+ return (eraType == AMETE_ALEM_ERA);
+}
+
+//-------------------------------------------------------------------------
+// Calendar framework
+//-------------------------------------------------------------------------
+
+int32_t
+EthiopicCalendar::handleGetExtendedYear()
+{
+ // Ethiopic calendar uses EXTENDED_YEAR aligned to
+ // Amelete Hihret year always.
+ int32_t eyear;
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else if (isAmeteAlemEra()) {
+ eyear = internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
+ - AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
+ } else {
+ // The year defaults to the epoch start, the era to AMETE_MIHRET
+ int32_t era = internalGet(UCAL_ERA, AMETE_MIHRET);
+ if (era == AMETE_MIHRET) {
+ eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
+ } else {
+ eyear = internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
+ }
+ }
+ return eyear;
+}
+
+void
+EthiopicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
+{
+ int32_t eyear, month, day, era, year;
+ jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
+
+ if (isAmeteAlemEra()) {
+ era = AMETE_ALEM;
+ year = eyear + AMETE_MIHRET_DELTA;
+ } else {
+ if (eyear > 0) {
+ era = AMETE_MIHRET;
+ year = eyear;
+ } else {
+ era = AMETE_ALEM;
+ year = eyear + AMETE_MIHRET_DELTA;
+ }
+ }
+
+ internalSet(UCAL_EXTENDED_YEAR, eyear);
+ internalSet(UCAL_ERA, era);
+ internalSet(UCAL_YEAR, year);
+ internalSet(UCAL_MONTH, month);
+ internalSet(UCAL_DATE, day);
+ internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
+}
+
+int32_t
+EthiopicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+ if (isAmeteAlemEra() && field == UCAL_ERA) {
+ return 0; // Only one era in this mode, era is always 0
+ }
+ return CECalendar::handleGetLimit(field, limitType);
+}
+
+const UDate EthiopicCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t EthiopicCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate EthiopicCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t EthiopicCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+UDate
+EthiopicCalendar::defaultCenturyStart() const
+{
+ initializeSystemDefaultCentury();
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+EthiopicCalendar::defaultCenturyStartYear() const
+{
+ initializeSystemDefaultCentury();
+ if (isAmeteAlemEra()) {
+ return fgSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
+ }
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+EthiopicCalendar::initializeSystemDefaultCentury()
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (!needsUpdate) {
+ return;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ EthiopicCalendar calendar(Locale("@calendar=ethiopic"), 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);
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ umtx_unlock(NULL);
+ }
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+}
+
+int32_t
+EthiopicCalendar::getJDEpochOffset() const
+{
+ return JD_EPOCH_OFFSET_AMETE_MIHRET;
+}
+
+
+#if 0
+// We do not want to introduce this API in ICU4C.
+// It was accidentally introduced in ICU4J as a public API.
+
+//-------------------------------------------------------------------------
+// Calendar system Conversion methods...
+//-------------------------------------------------------------------------
+
+int32_t
+EthiopicCalendar::ethiopicToJD(int32_t year, int32_t month, int32_t date)
+{
+ return ceToJD(year, month, date, JD_EPOCH_OFFSET_AMETE_MIHRET);
+}
+#endif
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.h b/Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.h
new file mode 100644
index 00000000000..01db826a79f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ethpccal.h
@@ -0,0 +1,300 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef ETHPCCAL_H
+#define ETHPCCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "cecal.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Implement the Ethiopic calendar system.
+ * @internal
+ */
+class EthiopicCalendar : public CECalendar {
+
+public:
+ /**
+ * Calendar type - use Amete Alem era for all the time or not
+ * @internal
+ */
+ enum EEraType {
+ AMETE_MIHRET_ERA,
+ AMETE_ALEM_ERA
+ };
+
+ /**
+ * Useful constants for EthiopicCalendar.
+ * @internal
+ */
+ enum EMonths {
+ /**
+ * Constant for &#x1218;&#x1235;&#x12a8;&#x1228;&#x121d;, the 1st month of the Ethiopic year.
+ */
+ MESKEREM,
+
+ /**
+ * Constant for &#x1325;&#x1245;&#x121d;&#x1275;, the 2nd month of the Ethiopic year.
+ */
+ TEKEMT,
+
+ /**
+ * Constant for &#x1285;&#x12f3;&#x122d;, the 3rd month of the Ethiopic year.
+ */
+ HEDAR,
+
+ /**
+ * Constant for &#x1273;&#x1285;&#x1223;&#x1225;, the 4th month of the Ethiopic year.
+ */
+ TAHSAS,
+
+ /**
+ * Constant for &#x1325;&#x122d;, the 5th month of the Ethiopic year.
+ */
+ TER,
+
+ /**
+ * Constant for &#x12e8;&#x12ab;&#x1272;&#x1275;, the 6th month of the Ethiopic year.
+ */
+ YEKATIT,
+
+ /**
+ * Constant for &#x1218;&#x130b;&#x1262;&#x1275;, the 7th month of the Ethiopic year.
+ */
+ MEGABIT,
+
+ /**
+ * Constant for &#x121a;&#x12eb;&#x12dd;&#x12eb;, the 8th month of the Ethiopic year.
+ */
+ MIAZIA,
+
+ /**
+ * Constant for &#x130d;&#x1295;&#x1266;&#x1275;, the 9th month of the Ethiopic year.
+ */
+ GENBOT,
+
+ /**
+ * Constant for &#x1230;&#x1294;, the 10th month of the Ethiopic year.
+ */
+ SENE,
+
+ /**
+ * Constant for &#x1210;&#x121d;&#x120c;, the 11th month of the Ethiopic year.
+ */
+ HAMLE,
+
+ /**
+ * Constant for &#x1290;&#x1210;&#x1234;, the 12th month of the Ethiopic year.
+ */
+ NEHASSA,
+
+ /**
+ * Constant for &#x1333;&#x1309;&#x121c;&#x1295;, the 13th month of the Ethiopic year.
+ */
+ PAGUMEN
+ };
+
+ enum EEras {
+ AMETE_ALEM, // Before the epoch
+ AMETE_MIHRET // After the epoch
+ };
+
+ /**
+ * Constructs a EthiopicCalendar 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 EthiopicCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @param type Whether this Ethiopic calendar use Amete Mihrret (default) or
+ * only use Amete Alem for all the time.
+ * @internal
+ */
+ EthiopicCalendar(const Locale& aLocale, UErrorCode& success, EEraType type = AMETE_MIHRET_ERA);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ EthiopicCalendar(const EthiopicCalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~EthiopicCalendar();
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @internal
+ */
+ virtual Calendar* clone() const;
+
+ /**
+ * return the calendar type, "ethiopic"
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+ /**
+ * Set Alem or Mihret era.
+ * @param onOff Set Amete Alem era if true, otherwise set Amete Mihret era.
+ * @internal
+ */
+ void setAmeteAlemEra (UBool onOff);
+
+ /**
+ * Return true if this calendar is set to the Amete Alem era.
+ * @return true if set to the Amete Alem era.
+ * @internal
+ */
+ UBool isAmeteAlemEra() const;
+
+protected:
+ //-------------------------------------------------------------------------
+ // Calendar framework
+ //-------------------------------------------------------------------------
+
+ /**
+ * Return the extended year defined by the current fields.
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+ /**
+ * Return the date offset from Julian
+ * @internal
+ */
+ virtual int32_t getJDEpochOffset() 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;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * 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);
+
+ /**
+ * When eraType is AMETE_ALEM_ERA, then this calendar use only AMETE_ALEM
+ * for the era. Otherwise (default), this calendar uses both AMETE_ALEM
+ * and AMETE_MIHRET.
+ *
+ * EXTENDED_YEAR AMETE_ALEM_ERA AMETE_MIHRET_ERA
+ * 0 Amete Alem 5500 Amete Alem 5500
+ * 1 Amete Mihret 1 Amete Alem 5501
+ */
+ EEraType eraType;
+
+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);
+
+#if 0
+// We do not want to introduce this API in ICU4C.
+// It was accidentally introduced in ICU4J as a public API.
+
+public:
+ //-------------------------------------------------------------------------
+ // Calendar system Conversion methods...
+ //-------------------------------------------------------------------------
+
+ /**
+ * Convert an Ethiopic year, month, and day to a Julian day.
+ *
+ * @param year the extended year
+ * @param month the month
+ * @param day the day
+ * @return Julian day
+ * @internal
+ */
+ int32_t ethiopicToJD(int32_t year, int32_t month, int32_t day);
+#endif
+};
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* ETHPCCAL_H */
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/fmtable.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/fmtable.cpp
new file mode 100644
index 00000000000..685fe2139cc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/fmtable.cpp
@@ -0,0 +1,866 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 <math.h>
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "unicode/measure.h"
+#include "unicode/curramt.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "decNumber.h"
+#include "digitlst.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==. 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) {
+ return dynamic_cast<const Measure*>(a) != NULL;
+}
+
+/**
+ * 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 Formattable* createArrayCopy(const Formattable* array, int32_t count) {
+ Formattable *result = new Formattable[count];
+ if (result != NULL) {
+ 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 void setError(UErrorCode& ec, UErrorCode err) {
+ if (U_SUCCESS(ec)) {
+ ec = err;
+ }
+}
+
+//
+// Common initialization code, shared by constructors.
+// Put everything into a known state.
+//
+void Formattable::init() {
+ fValue.fInt64 = 0;
+ fType = kLong;
+ fDecimalStr = NULL;
+ fDecimalNum = NULL;
+ fBogus.setToBogus();
+}
+
+// -------------------------------------
+// default constructor.
+// Creates a formattable object with a long value 0.
+
+Formattable::Formattable() {
+ init();
+}
+
+// -------------------------------------
+// Creates a formattable object with a Date instance.
+
+Formattable::Formattable(UDate date, ISDATE /*isDate*/)
+{
+ init();
+ fType = kDate;
+ fValue.fDate = date;
+}
+
+// -------------------------------------
+// Creates a formattable object with a double value.
+
+Formattable::Formattable(double value)
+{
+ init();
+ fType = kDouble;
+ fValue.fDouble = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with an int32_t value.
+
+Formattable::Formattable(int32_t value)
+{
+ init();
+ fValue.fInt64 = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with an int64_t value.
+
+Formattable::Formattable(int64_t value)
+{
+ init();
+ fType = kInt64;
+ fValue.fInt64 = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with a decimal number value from a string.
+
+Formattable::Formattable(const StringPiece &number, UErrorCode &status) {
+ init();
+ setDecimalNumber(number, status);
+}
+
+
+// -------------------------------------
+// Creates a formattable object with a UnicodeString instance.
+
+Formattable::Formattable(const UnicodeString& stringToCopy)
+{
+ init();
+ fType = kString;
+ fValue.fString = new UnicodeString(stringToCopy);
+}
+
+// -------------------------------------
+// Creates a formattable object with a UnicodeString* value.
+// (adopting symantics)
+
+Formattable::Formattable(UnicodeString* stringToAdopt)
+{
+ init();
+ fType = kString;
+ fValue.fString = stringToAdopt;
+}
+
+Formattable::Formattable(UObject* objectToAdopt)
+{
+ init();
+ fType = kObject;
+ fValue.fObject = objectToAdopt;
+}
+
+// -------------------------------------
+
+Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
+ : UObject(), fType(kArray)
+{
+ init();
+ fType = kArray;
+ fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
+ fValue.fArrayAndCount.fCount = count;
+}
+
+// -------------------------------------
+// copy constructor
+
+
+Formattable::Formattable(const Formattable &source)
+ : UObject(*this)
+{
+ init();
+ *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;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ if (source.fDecimalNum != NULL) {
+ fDecimalNum = new DigitList(*source.fDecimalNum);
+ }
+ if (source.fDecimalStr != NULL) {
+ fDecimalStr = new CharString(*source.fDecimalStr, status);
+ if (U_FAILURE(status)) {
+ delete fDecimalStr;
+ fDecimalStr = NULL;
+ }
+ }
+ }
+ 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:
+ if (fValue.fObject == NULL || that.fValue.fObject == NULL) {
+ equal = FALSE;
+ } else {
+ equal = objectEquals(fValue.fObject, that.fValue.fObject);
+ }
+ break;
+ }
+
+ // TODO: compare digit lists if numeric.
+ 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;
+ }
+
+ fType = kLong;
+ fValue.fInt64 = 0;
+ delete fDecimalStr;
+ fDecimalStr = NULL;
+ delete fDecimalNum;
+ fDecimalNum = NULL;
+}
+
+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:
+ if (fValue.fObject == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ // 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;
+ }
+}
+
+// -------------------------------------
+// Maximum int that can be represented exactly in a double. (53 bits)
+// Larger ints may be rounded to a near-by value as not all are representable.
+// TODO: move this constant elsewhere, possibly configure it for different
+// floating point formats, if any non-standard ones are still in use.
+static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL;
+
+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 > (double)U_INT64_MAX) {
+ status = U_INVALID_FORMAT_ERROR;
+ return U_INT64_MAX;
+ } else if (fValue.fDouble < (double)U_INT64_MIN) {
+ status = U_INVALID_FORMAT_ERROR;
+ return U_INT64_MIN;
+ } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) {
+ int64_t val = fDecimalNum->getInt64();
+ if (val != 0) {
+ return val;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN;
+ }
+ } else {
+ return (int64_t)fValue.fDouble;
+ }
+ case Formattable::kObject:
+ if (fValue.fObject == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ 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:
+ if (fValue.fObject == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ // 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 {
+ if (fValue.fString == NULL) {
+ setError(status, U_MEMORY_ALLOCATION_ERROR);
+ } else {
+ result = *fValue.fString;
+ }
+ }
+ return result;
+}
+
+// -------------------------------------
+const UnicodeString&
+Formattable::getString(UErrorCode& status) const
+{
+ if (fType != kString) {
+ setError(status, U_INVALID_FORMAT_ERROR);
+ return *getBogus();
+ }
+ if (fValue.fString == NULL) {
+ setError(status, U_MEMORY_ALLOCATION_ERROR);
+ return *getBogus();
+ }
+ return *fValue.fString;
+}
+
+// -------------------------------------
+UnicodeString&
+Formattable::getString(UErrorCode& status)
+{
+ if (fType != kString) {
+ setError(status, U_INVALID_FORMAT_ERROR);
+ return *getBogus();
+ }
+ if (fValue.fString == NULL) {
+ setError(status, U_MEMORY_ALLOCATION_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 :-( */
+}
+
+
+// --------------------------------------
+StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return "";
+ }
+ if (fDecimalStr != NULL) {
+ return fDecimalStr->toStringPiece();
+ }
+
+ if (fDecimalNum == NULL) {
+ // No decimal number for the formattable yet. Which means the value was
+ // set directly by the user as an int, int64 or double. If the value came
+ // from parsing, or from the user setting a decimal number, fDecimalNum
+ // would already be set.
+ //
+ fDecimalNum = new DigitList;
+ if (fDecimalNum == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return "";
+ }
+
+ switch (fType) {
+ case kDouble:
+ fDecimalNum->set(this->getDouble());
+ break;
+ case kLong:
+ fDecimalNum->set(this->getLong());
+ break;
+ case kInt64:
+ fDecimalNum->set(this->getInt64());
+ break;
+ default:
+ // The formattable's value is not a numeric type.
+ status = U_INVALID_STATE_ERROR;
+ return "";
+ }
+ }
+
+ fDecimalStr = new CharString;
+ if (fDecimalStr == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return "";
+ }
+ fDecimalNum->getDecimal(*fDecimalStr, status);
+
+ return fDecimalStr->toStringPiece();
+}
+
+
+
+// ---------------------------------------
+void
+Formattable::adoptDigitList(DigitList *dl) {
+ dispose();
+
+ fDecimalNum = dl;
+
+ // Set the value into the Union of simple type values.
+ // Cannot use the set() functions because they would delete the fDecimalNum value,
+
+ if (fDecimalNum->fitsIntoLong(FALSE)) {
+ fType = kLong;
+ fValue.fInt64 = fDecimalNum->getLong();
+ } else if (fDecimalNum->fitsIntoInt64(FALSE)) {
+ fType = kInt64;
+ fValue.fInt64 = fDecimalNum->getInt64();
+ } else {
+ fType = kDouble;
+ fValue.fDouble = fDecimalNum->getDouble();
+ }
+}
+
+
+// ---------------------------------------
+void
+Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ dispose();
+
+ // Copy the input string and nul-terminate it.
+ // The decNumber library requires nul-terminated input. StringPiece input
+ // is not guaranteed nul-terminated. Too bad.
+ // CharString automatically adds the nul.
+ DigitList *dnum = new DigitList();
+ if (dnum == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ dnum->set(CharString(numberString, status).toStringPiece(), status);
+ if (U_FAILURE(status)) {
+ delete dnum;
+ return; // String didn't contain a decimal number.
+ }
+ adoptDigitList(dnum);
+
+ // Note that we do not hang on to the caller's input string.
+ // If we are asked for the string, we will regenerate one from fDecimalNum.
+}
+
+#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-4.8.1/i18n/fmtable_cnv.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/fmtable_cnv.cpp
new file mode 100644
index 00000000000..8e9645402e5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/fmtable_cnv.cpp
@@ -0,0 +1,44 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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)
+{
+ init();
+ fType = kString;
+ 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-4.8.1/i18n/format.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/format.cpp
new file mode 100644
index 00000000000..701b489fff7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/format.cpp
@@ -0,0 +1,213 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 <typeinfo> // for 'typeid' to work
+
+#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)
+{
+ if (this != &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);
+}
+
+// -------------------------------------
+// Default implementation sets unsupported error; subclasses should
+// override.
+
+UnicodeString&
+Format::format(const Formattable& /* unused obj */,
+ UnicodeString& toAppendTo,
+ FieldPositionIterator* /* unused posIter */,
+ UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return toAppendTo;
+}
+
+// -------------------------------------
+// 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 typeid(*this) == typeid(that);
+}
+//---------------------------------------
+
+/**
+ * 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-4.8.1/i18n/fphdlimp.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.cpp
new file mode 100644
index 00000000000..9d94a411488
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.cpp
@@ -0,0 +1,120 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "fphdlimp.h"
+#include "uvectr32.h"
+
+U_NAMESPACE_BEGIN
+
+// utility FieldPositionHandler
+// base class, null implementation
+
+FieldPositionHandler::~FieldPositionHandler() {
+}
+
+void
+FieldPositionHandler::addAttribute(int32_t, int32_t, int32_t) {
+}
+
+void
+FieldPositionHandler::shiftLast(int32_t) {
+}
+
+UBool
+FieldPositionHandler::isRecording(void) {
+ return FALSE;
+}
+
+
+// utility subclass FieldPositionOnlyHandler
+
+FieldPositionOnlyHandler::FieldPositionOnlyHandler(FieldPosition& _pos)
+ : pos(_pos) {
+}
+
+FieldPositionOnlyHandler::~FieldPositionOnlyHandler() {
+}
+
+void
+FieldPositionOnlyHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
+ if (pos.getField() == id) {
+ pos.setBeginIndex(start);
+ pos.setEndIndex(limit);
+ }
+}
+
+void
+FieldPositionOnlyHandler::shiftLast(int32_t delta) {
+ if (delta != 0 && pos.getField() != FieldPosition::DONT_CARE && pos.getBeginIndex() != -1) {
+ pos.setBeginIndex(delta + pos.getBeginIndex());
+ pos.setEndIndex(delta + pos.getEndIndex());
+ }
+}
+
+UBool
+FieldPositionOnlyHandler::isRecording(void) {
+ return pos.getField() != FieldPosition::DONT_CARE;
+}
+
+
+// utility subclass FieldPositionIteratorHandler
+
+FieldPositionIteratorHandler::FieldPositionIteratorHandler(FieldPositionIterator* posIter,
+ UErrorCode& _status)
+ : iter(posIter), vec(NULL), status(_status) {
+ if (iter && U_SUCCESS(status)) {
+ vec = new UVector32(status);
+ }
+}
+
+FieldPositionIteratorHandler::~FieldPositionIteratorHandler() {
+ // setData adopts the vec regardless of status, so it's safe to null it
+ if (iter) {
+ iter->setData(vec, status);
+ }
+ // if iter is null, we never allocated vec, so no need to free it
+ vec = NULL;
+}
+
+void
+FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
+ if (iter && U_SUCCESS(status) && start < limit) {
+ int32_t size = vec->size();
+ vec->addElement(id, status);
+ vec->addElement(start, status);
+ vec->addElement(limit, status);
+ if (!U_SUCCESS(status)) {
+ vec->setSize(size);
+ }
+ }
+}
+
+void
+FieldPositionIteratorHandler::shiftLast(int32_t delta) {
+ if (U_SUCCESS(status) && delta != 0) {
+ int32_t i = vec->size();
+ if (i > 0) {
+ --i;
+ vec->setElementAt(delta + vec->elementAti(i), i);
+ --i;
+ vec->setElementAt(delta + vec->elementAti(i), i);
+ }
+ }
+}
+
+UBool
+FieldPositionIteratorHandler::isRecording(void) {
+ return U_SUCCESS(status);
+}
+
+U_NAMESPACE_END
+
+#endif /* !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.h b/Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.h
new file mode 100644
index 00000000000..cd5c314a888
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/fphdlimp.h
@@ -0,0 +1,73 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef FPHDLIMP_H
+#define FPHDLIMP_H
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/utypes.h"
+#include "unicode/fieldpos.h"
+#include "unicode/fpositer.h"
+
+U_NAMESPACE_BEGIN
+
+// utility FieldPositionHandler
+// base class, null implementation
+
+class FieldPositionHandler: public UMemory {
+ public:
+ virtual ~FieldPositionHandler();
+ virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
+ virtual void shiftLast(int32_t delta);
+ virtual UBool isRecording(void);
+};
+
+
+// utility subclass FieldPositionOnlyHandler
+
+class FieldPositionOnlyHandler : public FieldPositionHandler {
+ FieldPosition& pos;
+
+ public:
+ FieldPositionOnlyHandler(FieldPosition& pos);
+ virtual ~FieldPositionOnlyHandler();
+
+ virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
+ virtual void shiftLast(int32_t delta);
+ virtual UBool isRecording(void);
+};
+
+
+// utility subclass FieldPositionIteratorHandler
+
+class FieldPositionIteratorHandler : public FieldPositionHandler {
+ FieldPositionIterator* iter; // can be NULL
+ UVector32* vec;
+ UErrorCode status;
+
+ // Note, we keep a reference to status, so if status is on the stack, we have
+ // to be destroyed before status goes out of scope. Easiest thing is to
+ // allocate us on the stack in the same (or narrower) scope as status has.
+ // This attempts to encourage that by blocking heap allocation.
+ void *operator new(size_t s);
+ void *operator new[](size_t s);
+
+ public:
+ FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status);
+ ~FieldPositionIteratorHandler();
+
+ virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
+ virtual void shiftLast(int32_t delta);
+ virtual UBool isRecording(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* !UCONFIG_NO_FORMATTING */
+
+#endif /* FPHDLIMP_H */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/fpositer.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/fpositer.cpp
new file mode 100644
index 00000000000..69712642b22
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/fpositer.cpp
@@ -0,0 +1,109 @@
+/*
+******************************************************************************
+* Copyright (C) 2009-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+******************************************************************************
+* Date Name Description
+* 12/14/09 doug Creation.
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/fpositer.h"
+#include "cmemory.h"
+#include "uvectr32.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(FieldPositionIterator)
+
+FieldPositionIterator::~FieldPositionIterator() {
+ delete data;
+ data = NULL;
+ pos = -1;
+}
+
+FieldPositionIterator::FieldPositionIterator()
+ : data(NULL), pos(-1) {
+}
+
+FieldPositionIterator::FieldPositionIterator(const FieldPositionIterator &rhs)
+ : UObject(rhs), data(NULL), pos(rhs.pos) {
+
+ if (rhs.data) {
+ UErrorCode status = U_ZERO_ERROR;
+ data = new UVector32(status);
+ data->assign(*rhs.data, status);
+ if (status != U_ZERO_ERROR) {
+ delete data;
+ data = NULL;
+ pos = -1;
+ }
+ }
+}
+
+UBool FieldPositionIterator::operator==(const FieldPositionIterator &rhs) const {
+ if (&rhs == this) {
+ return TRUE;
+ }
+ if (pos != rhs.pos) {
+ return FALSE;
+ }
+ if (!data) {
+ return rhs.data == NULL;
+ }
+ return rhs.data ? data->operator==(*rhs.data) : FALSE;
+}
+
+void FieldPositionIterator::setData(UVector32 *adopt, UErrorCode& status) {
+ // Verify that adopt has valid data, and update status if it doesn't.
+ if (U_SUCCESS(status)) {
+ if (adopt) {
+ if ((adopt->size() % 3) != 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ for (int i = 1; i < adopt->size(); i += 3) {
+ if (adopt->elementAti(i) >= adopt->elementAti(i+1)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // We own the data, even if status is in error, so we need to delete it now
+ // if we're not keeping track of it.
+ if (!U_SUCCESS(status)) {
+ delete adopt;
+ return;
+ }
+
+ delete data;
+ data = adopt;
+ pos = adopt == NULL ? -1 : 0;
+}
+
+UBool FieldPositionIterator::next(FieldPosition& fp) {
+ if (pos == -1) {
+ return FALSE;
+ }
+
+ fp.setField(data->elementAti(pos++));
+ fp.setBeginIndex(data->elementAti(pos++));
+ fp.setEndIndex(data->elementAti(pos++));
+
+ if (pos == data->size()) {
+ pos = -1;
+ }
+
+ return TRUE;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.cpp
new file mode 100644
index 00000000000..03d71834762
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.cpp
@@ -0,0 +1,125 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2008, 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-4.8.1/i18n/funcrepl.h b/Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.h
new file mode 100644
index 00000000000..ff00b55abfb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/funcrepl.h
@@ -0,0 +1,119 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2011, 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.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/gregocal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/gregocal.cpp
new file mode 100644
index 00000000000..3bc77cf1494
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/gregocal.cpp
@@ -0,0 +1,1356 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 int16_t kNumDays[]
+= {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year
+static const int16_t kLeapNumDays[]
+= {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year
+static const int8_t kMonthLength[]
+= {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
+static const int8_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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // 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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
+};
+
+/*
+* <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(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)ClockMath::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) ClockMath::floorDivide(4*julianEpochDay + 1464, 1461);
+
+ // Compute the Julian calendar day number for January 1, eyear
+ int32_t january1 = 365*(eyear-1) + ClockMath::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 += ClockMath::floorDivide(month, 12, month);
+ }
+
+ UBool isLeap = eyear%4 == 0;
+ int32_t y = eyear-1;
+ int32_t julianDay = 365*y + ClockMath::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 += ClockMath::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 ClockMath::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 + ClockMath::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 + ClockMath::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() {
+ // the year to return
+ int32_t year = kEpochYear;
+
+ // year field to use
+ int32_t yearField = UCAL_EXTENDED_YEAR;
+
+ // There are three separate fields which could be used to
+ // derive the proper year. Use the one most recently set.
+ if (fStamp[yearField] < fStamp[UCAL_YEAR])
+ yearField = UCAL_YEAR;
+ if (fStamp[yearField] < fStamp[UCAL_YEAR_WOY])
+ yearField = UCAL_YEAR_WOY;
+
+ // based on the "best" year field, get the year
+ switch(yearField) {
+ 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.
+ 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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ 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-4.8.1/i18n/gregoimp.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/gregoimp.cpp
new file mode 100644
index 00000000000..08a3fbcef4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/gregoimp.cpp
@@ -0,0 +1,328 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2003-2008, 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 ClockMath::floorDivide(int32_t numerator, int32_t denominator) {
+ return (numerator >= 0) ?
+ numerator / denominator : ((numerator + 1) / denominator) - 1;
+}
+
+int32_t ClockMath::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 ClockMath::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 + ClockMath::floorDivide(y, 4) + (JULIAN_1_CE - 3) + // Julian cal
+ ClockMath::floorDivide(y, 400) - ClockMath::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 = ClockMath::floorDivide(day, 146097, doy); // 400-year cycle length
+ int32_t n100 = ClockMath::floorDivide(doy, 36524, doy); // 100-year cycle length
+ int32_t n4 = ClockMath::floorDivide(doy, 1461, doy); // 4-year cycle length
+ int32_t n1 = ClockMath::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 = ClockMath::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;
+ ClockMath::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-4.8.1/i18n/gregoimp.h b/Build/source/libs/icu/icu-4.8.1/i18n/gregoimp.h
new file mode 100644
index 00000000000..f65d1410139
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/gregoimp.h
@@ -0,0 +1,364 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2003-2008, 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. Formerly just named 'Math'.
+ * @internal
+ */
+class ClockMath {
+ 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 ClockMath::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 + ClockMath::floorDivide(millis, (double)kOneDay));
+}
+
+inline int32_t Grego::gregorianShift(int32_t eyear) {
+ int32_t y = eyear-1;
+ int32_t gregShift = ClockMath::floorDivide(y, 400) - ClockMath::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-4.8.1/i18n/hebrwcal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/hebrwcal.cpp
new file mode 100644
index 00000000000..3a6ef439412
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/hebrwcal.cpp
@@ -0,0 +1,758 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2008, 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
+ { -5000000, -5000000, 5000000, 5000000}, // YEAR
+ { 0, 0, 12, 12}, // MONTH
+ { 1, 1, 51, 56}, // WEEK_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // 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
+ { -5000000, -5000000, 5000000, 5000000}, // 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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
+};
+
+/**
+* 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 int8_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 int16_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 int16_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
+
+ int64_t frac = (int64_t)months * MONTH_FRACT + BAHARAD; // Fractional part of day #
+ day = months * 29 + (int32_t)(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;
+ int32_t momax = sizeof(MONTH_START) / (3 * sizeof(MONTH_START[0][0]));
+ while (month < momax && dayOfYear > ( isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
+ month++;
+ }
+ if (month >= momax || month<=0) {
+ // TODO: I found dayOfYear could be out of range when
+ // a large value is set to julianDay. I patched startOfYear
+ // to reduce the chace, but it could be still reproduced either
+ // by startOfYear or other places. For now, we check
+ // the month is in valid range to avoid out of array index
+ // access problem here. However, we need to carefully review
+ // the calendar implementation to check the extreme limit of
+ // each calendar field and the code works well for any values
+ // in the valid value range. -yoshito
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ 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.
+ 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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ 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-4.8.1/i18n/hebrwcal.h b/Build/source/libs/icu/icu-4.8.1/i18n/hebrwcal.h
new file mode 100644
index 00000000000..76f100fea95
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/hebrwcal.h
@@ -0,0 +1,486 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2009, 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 U_I18N_API 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
+ */
+ 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);
+
+ /**
+ * @internal
+ */
+ static UBool isLeapYear(int32_t year) ;
+
+ 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 int32_t monthsInYear(int32_t year) ;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+//eof
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/i18n.rc b/Build/source/libs/icu/icu-4.8.1/i18n/i18n.rc
new file mode 100644
index 00000000000..1b624ad6b55
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-2010 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, U_ICU_VERSION_BUILDLEVEL_NUM
+ PRODUCTVERSION U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, U_ICU_VERSION_BUILDLEVEL_NUM
+ 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", ICU_COMPANY "\0"
+ VALUE "FileDescription", ICU_PRODUCT_PREFIX " I18N DLL\0"
+ VALUE "FileVersion", CommaVersionString(U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, U_ICU_VERSION_BUILDLEVEL_NUM)
+ 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", ICU_PRODUCT "\0"
+ VALUE "ProductVersion", CommaVersionString(U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, U_ICU_VERSION_BUILDLEVEL_NUM)
+ 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-4.8.1/i18n/i18n.vcxproj b/Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj
new file mode 100644
index 00000000000..e9e32c1b2b4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj
@@ -0,0 +1,1527 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{0178B127-6269-407D-B112-93877BB62776}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\..\..\lib\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\x86\Release\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\..\..\lib\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\x86\Debug\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\x64\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\x64\Release\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\x64\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\x64\Debug\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\..\..\lib\icuin.tlb</TypeLibraryName>
+ </Midl>
+ <ClCompile>
+ <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>U_ATTRIBUTE_DEPRECATED=;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_I18N_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <DisableLanguageExtensions>true</DisableLanguageExtensions>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <PrecompiledHeaderOutputFile>.\x86\Release/i18n.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\x86\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\x86\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\x86\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>..\..\bin\icuin48.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>.\..\..\lib\icuin.pdb</ProgramDatabaseFile>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <BaseAddress>0x4a900000</BaseAddress>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>..\..\lib\icuin.lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\..\..\lib\icuind.tlb</TypeLibraryName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>U_ATTRIBUTE_DEPRECATED=;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_I18N_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <DisableLanguageExtensions>true</DisableLanguageExtensions>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <PrecompiledHeaderOutputFile>.\x86\Debug/i18n.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\x86\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\x86\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\x86\Debug/</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>..\..\bin\icuin48d.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>.\..\..\lib\icuind.pdb</ProgramDatabaseFile>
+ <BaseAddress>0x4a900000</BaseAddress>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>..\..\lib\icuind.lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\..\..\lib64\icuin.tlb</TypeLibraryName>
+ </Midl>
+ <ClCompile>
+ <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>U_ATTRIBUTE_DEPRECATED=;WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_I18N_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <DisableLanguageExtensions>true</DisableLanguageExtensions>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <PrecompiledHeaderOutputFile>.\x64\Release/i18n.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\x64\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\x64\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\x64\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>..\..\bin64\icuin48.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>.\..\..\lib64\icuin.pdb</ProgramDatabaseFile>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <BaseAddress>0x4a900000</BaseAddress>
+ <ImportLibrary>..\..\lib64\icuin.lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\..\..\lib64\icuind.tlb</TypeLibraryName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>U_ATTRIBUTE_DEPRECATED=;WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_I18N_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <DisableLanguageExtensions>true</DisableLanguageExtensions>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <PrecompiledHeaderOutputFile>.\x64\Debug/i18n.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\x64\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\x64\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\x64\Debug/</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>..\..\bin64\icuin48d.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>.\..\..\lib64\icuind.pdb</ProgramDatabaseFile>
+ <BaseAddress>0x4a900000</BaseAddress>
+ <ImportLibrary>..\..\lib64\icuind.lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="alphaindex.cpp" />
+ <ClCompile Include="bms.cpp" />
+ <ClCompile Include="bmsearch.cpp" />
+ <ClCompile Include="bocsu.cpp" />
+ <ClCompile Include="coleitr.cpp" />
+ <ClCompile Include="coll.cpp" />
+ <ClCompile Include="colldata.cpp" />
+ <ClCompile Include="search.cpp" />
+ <ClCompile Include="sortkey.cpp" />
+ <ClCompile Include="stsearch.cpp" />
+ <ClCompile Include="tblcoll.cpp" />
+ <ClCompile Include="tzfmt.cpp" />
+ <ClCompile Include="tzgnames.cpp" />
+ <ClCompile Include="tznames.cpp" />
+ <ClCompile Include="tznames_impl.cpp" />
+ <ClCompile Include="ucol.cpp" />
+ <ClCompile Include="ucol_bld.cpp" />
+ <ClCompile Include="ucol_cnt.cpp" />
+ <ClCompile Include="ucol_elm.cpp" />
+ <ClCompile Include="ucol_res.cpp" />
+ <ClCompile Include="ucol_sit.cpp" />
+ <ClCompile Include="ucol_tok.cpp" />
+ <ClCompile Include="ucol_wgt.cpp" />
+ <ClCompile Include="ucoleitr.cpp" />
+ <ClCompile Include="usearch.cpp" />
+ <ClCompile Include="astro.cpp" />
+ <ClCompile Include="basictz.cpp" />
+ <ClCompile Include="buddhcal.cpp" />
+ <ClCompile Include="calendar.cpp" />
+ <ClCompile Include="cecal.cpp" />
+ <ClCompile Include="chnsecal.cpp" />
+ <ClCompile Include="choicfmt.cpp" />
+ <ClCompile Include="coptccal.cpp" />
+ <ClCompile Include="curramt.cpp" />
+ <ClCompile Include="currfmt.cpp" />
+ <ClCompile Include="currpinf.cpp" />
+ <ClCompile Include="currunit.cpp" />
+ <ClCompile Include="datefmt.cpp" />
+ <ClCompile Include="dcfmtsym.cpp" />
+ <ClCompile Include="decContext.c" />
+ <ClCompile Include="decfmtst.cpp" />
+ <ClCompile Include="decimfmt.cpp" />
+ <ClCompile Include="decNumber.c" />
+ <ClCompile Include="digitlst.cpp" />
+ <ClCompile Include="dtfmtsym.cpp" />
+ <ClCompile Include="dtitvfmt.cpp" />
+ <ClCompile Include="dtitvinf.cpp" />
+ <ClCompile Include="dtptngen.cpp" />
+ <ClCompile Include="dtrule.cpp" />
+ <ClCompile Include="ethpccal.cpp" />
+ <ClCompile Include="fmtable.cpp" />
+ <ClCompile Include="fmtable_cnv.cpp" />
+ <ClCompile Include="format.cpp" />
+ <ClCompile Include="fphdlimp.cpp" />
+ <ClCompile Include="fpositer.cpp" />
+ <ClCompile Include="gregocal.cpp" />
+ <ClCompile Include="gregoimp.cpp" />
+ <ClCompile Include="hebrwcal.cpp" />
+ <ClCompile Include="indiancal.cpp" />
+ <ClCompile Include="islamcal.cpp" />
+ <ClCompile Include="japancal.cpp" />
+ <ClCompile Include="locdspnm.cpp" />
+ <ClCompile Include="measfmt.cpp" />
+ <ClCompile Include="measure.cpp" />
+ <ClCompile Include="msgfmt.cpp" />
+ <ClCompile Include="nfrs.cpp" />
+ <ClCompile Include="nfrule.cpp" />
+ <ClCompile Include="nfsubs.cpp" />
+ <ClCompile Include="numfmt.cpp" />
+ <ClCompile Include="numsys.cpp" />
+ <ClCompile Include="olsontz.cpp" />
+ <ClCompile Include="persncal.cpp" />
+ <ClCompile Include="plurfmt.cpp" />
+ <ClCompile Include="plurrule.cpp" />
+ <ClCompile Include="rbnf.cpp" />
+ <ClCompile Include="rbtz.cpp" />
+ <ClCompile Include="reldtfmt.cpp" />
+ <ClCompile Include="selfmt.cpp" />
+ <ClCompile Include="simpletz.cpp" />
+ <ClCompile Include="smpdtfmt.cpp" />
+ <ClCompile Include="smpdtfst.cpp" />
+ <ClCompile Include="taiwncal.cpp" />
+ <ClCompile Include="timezone.cpp" />
+ <ClCompile Include="tmunit.cpp" />
+ <ClCompile Include="tmutamt.cpp" />
+ <ClCompile Include="tmutfmt.cpp" />
+ <ClCompile Include="tzrule.cpp" />
+ <ClCompile Include="tztrans.cpp" />
+ <ClCompile Include="ucal.cpp" />
+ <ClCompile Include="ucurr.cpp" />
+ <ClCompile Include="udat.cpp" />
+ <ClCompile Include="udateintervalformat.cpp" />
+ <ClCompile Include="udatpg.cpp" />
+ <ClCompile Include="ulocdata.c" />
+ <ClCompile Include="umsg.cpp" />
+ <ClCompile Include="unum.cpp" />
+ <ClCompile Include="upluralrules.cpp" />
+ <ClCompile Include="utmscale.c" />
+ <ClCompile Include="vtzone.cpp" />
+ <ClCompile Include="vzone.cpp" />
+ <ClCompile Include="windtfmt.cpp">
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</DisableLanguageExtensions>
+ </ClCompile>
+ <ClCompile Include="winnmfmt.cpp">
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</DisableLanguageExtensions>
+ </ClCompile>
+ <ClCompile Include="wintzimpl.cpp">
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</DisableLanguageExtensions>
+ </ClCompile>
+ <ClCompile Include="zonemeta.cpp" />
+ <ClCompile Include="zrule.cpp" />
+ <ClCompile Include="ztrans.cpp" />
+ <ClCompile Include="ucln_in.c">
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</DisableLanguageExtensions>
+ <DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</DisableLanguageExtensions>
+ </ClCompile>
+ <ClCompile Include="regexcmp.cpp" />
+ <ClCompile Include="regexst.cpp" />
+ <ClCompile Include="regextxt.cpp" />
+ <ClCompile Include="rematch.cpp" />
+ <ClCompile Include="repattrn.cpp" />
+ <ClCompile Include="uregex.cpp" />
+ <ClCompile Include="uregexc.cpp" />
+ <ClCompile Include="anytrans.cpp" />
+ <ClCompile Include="brktrans.cpp" />
+ <ClCompile Include="casetrn.cpp" />
+ <ClCompile Include="cpdtrans.cpp" />
+ <ClCompile Include="esctrn.cpp" />
+ <ClCompile Include="funcrepl.cpp" />
+ <ClCompile Include="name2uni.cpp" />
+ <ClCompile Include="nortrans.cpp" />
+ <ClCompile Include="nultrans.cpp" />
+ <ClCompile Include="quant.cpp" />
+ <ClCompile Include="rbt.cpp" />
+ <ClCompile Include="rbt_data.cpp" />
+ <ClCompile Include="rbt_pars.cpp" />
+ <ClCompile Include="rbt_rule.cpp" />
+ <ClCompile Include="rbt_set.cpp" />
+ <ClCompile Include="remtrans.cpp" />
+ <ClCompile Include="strmatch.cpp" />
+ <ClCompile Include="strrepl.cpp" />
+ <ClCompile Include="titletrn.cpp" />
+ <ClCompile Include="tolowtrn.cpp" />
+ <ClCompile Include="toupptrn.cpp" />
+ <ClCompile Include="translit.cpp" />
+ <ClCompile Include="transreg.cpp" />
+ <ClCompile Include="tridpars.cpp" />
+ <ClCompile Include="unesctrn.cpp" />
+ <ClCompile Include="uni2name.cpp" />
+ <ClCompile Include="utrans.cpp" />
+ <ClCompile Include="csdetect.cpp" />
+ <ClCompile Include="csmatch.cpp" />
+ <ClCompile Include="csr2022.cpp" />
+ <ClCompile Include="csrecog.cpp" />
+ <ClCompile Include="csrmbcs.cpp" />
+ <ClCompile Include="csrsbcs.cpp" />
+ <ClCompile Include="csrucode.cpp" />
+ <ClCompile Include="csrutf8.cpp" />
+ <ClCompile Include="inputext.cpp" />
+ <ClCompile Include="ucsdet.cpp" />
+ <ClCompile Include="uspoof.cpp" />
+ <ClCompile Include="uspoof_build.cpp" />
+ <ClCompile Include="uspoof_conf.cpp" />
+ <ClCompile Include="uspoof_impl.cpp" />
+ <ClCompile Include="uspoof_wsconf.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="unicode\alphaindex.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\bms.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\bmsearch.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="bocsu.h" />
+ <CustomBuild Include="unicode\coleitr.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\coll.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\colldata.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\search.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\sortkey.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\stsearch.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tblcoll.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucol.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="tzfmt.h" />
+ <ClInclude Include="tzgnames.h" />
+ <ClInclude Include="tznames.h" />
+ <ClInclude Include="tznames_impl.h" />
+ <ClInclude Include="ucol_bld.h" />
+ <ClInclude Include="ucol_cnt.h" />
+ <ClInclude Include="ucol_elm.h" />
+ <ClInclude Include="ucol_imp.h" />
+ <ClInclude Include="ucol_tok.h" />
+ <ClInclude Include="ucol_wgt.h" />
+ <CustomBuild Include="unicode\ucoleitr.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\usearch.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="usrchimp.h" />
+ <ClInclude Include="astro.h" />
+ <CustomBuild Include="unicode\basictz.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="buddhcal.h" />
+ <CustomBuild Include="unicode\calendar.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="cecal.h" />
+ <ClInclude Include="chnsecal.h" />
+ <CustomBuild Include="unicode\choicfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="coptccal.h" />
+ <CustomBuild Include="unicode\curramt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="currfmt.h" />
+ <CustomBuild Include="unicode\currpinf.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\currunit.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\datefmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dcfmtsym.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="decContext.h" />
+ <ClInclude Include="decfmtst.h" />
+ <CustomBuild Include="unicode\decimfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="decNumber.h" />
+ <ClInclude Include="decNumberLocal.h" />
+ <ClInclude Include="digitlst.h" />
+ <CustomBuild Include="unicode\dtfmtsym.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="dtitv_impl.h" />
+ <CustomBuild Include="unicode\dtitvfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtitvinf.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtptngen.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="dtptngen_impl.h" />
+ <CustomBuild Include="unicode\dtrule.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="ethpccal.h" />
+ <CustomBuild Include="unicode\fieldpos.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\fmtable.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\format.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="fphdlimp.h" />
+ <CustomBuild Include="unicode\fpositer.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\gregocal.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="gregoimp.h" />
+ <ClInclude Include="hebrwcal.h" />
+ <ClInclude Include="indiancal.h" />
+ <ClInclude Include="islamcal.h" />
+ <ClInclude Include="japancal.h" />
+ <CustomBuild Include="unicode\locdspnm.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\measfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\measunit.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\measure.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\msgfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="msgfmt_impl.h" />
+ <ClInclude Include="nfrlist.h" />
+ <ClInclude Include="nfrs.h" />
+ <ClInclude Include="nfrule.h" />
+ <ClInclude Include="nfsubs.h" />
+ <CustomBuild Include="unicode\numfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\numsys.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="olsontz.h" />
+ <ClInclude Include="persncal.h" />
+ <CustomBuild Include="unicode\plurfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\plurrule.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="plurrule_impl.h" />
+ <CustomBuild Include="unicode\rbnf.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\rbtz.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="reldtfmt.h" />
+ <CustomBuild Include="unicode\selfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\simpletz.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\smpdtfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="smpdtfst.h" />
+ <ClInclude Include="taiwncal.h" />
+ <CustomBuild Include="unicode\timezone.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tmunit.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tmutamt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tmutfmt.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tzrule.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tztrans.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucal.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucurr.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="ucurrimp.h" />
+ <CustomBuild Include="unicode\udat.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\udateintervalformat.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\udatpg.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\uldnames.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ulocdata.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\umsg.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="umsg_imp.h" />
+ <CustomBuild Include="unicode\unum.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\upluralrules.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\utmscale.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\vtzone.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="vzone.h" />
+ <ClInclude Include="windtfmt.h" />
+ <ClInclude Include="winnmfmt.h" />
+ <ClInclude Include="wintzimpl.h" />
+ <ClInclude Include="zonemeta.h" />
+ <ClInclude Include="zrule.h" />
+ <ClInclude Include="ztrans.h" />
+ <ClInclude Include="ucln_in.h" />
+ <CustomBuild Include="unicode\regex.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="regexcmp.h" />
+ <ClInclude Include="regexcst.h" />
+ <ClInclude Include="regeximp.h" />
+ <ClInclude Include="regexst.h" />
+ <ClInclude Include="regextxt.h" />
+ <CustomBuild Include="unicode\uregex.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="anytrans.h" />
+ <ClInclude Include="brktrans.h" />
+ <ClInclude Include="casetrn.h" />
+ <ClInclude Include="cpdtrans.h" />
+ <ClInclude Include="esctrn.h" />
+ <ClInclude Include="funcrepl.h" />
+ <ClInclude Include="name2uni.h" />
+ <ClInclude Include="nortrans.h" />
+ <ClInclude Include="nultrans.h" />
+ <ClInclude Include="quant.h" />
+ <ClInclude Include="rbt.h" />
+ <ClInclude Include="rbt_data.h" />
+ <ClInclude Include="rbt_pars.h" />
+ <ClInclude Include="rbt_rule.h" />
+ <ClInclude Include="rbt_set.h" />
+ <ClInclude Include="remtrans.h" />
+ <ClInclude Include="strmatch.h" />
+ <ClInclude Include="strrepl.h" />
+ <ClInclude Include="titletrn.h" />
+ <ClInclude Include="tolowtrn.h" />
+ <ClInclude Include="toupptrn.h" />
+ <CustomBuild Include="unicode\translit.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="transreg.h" />
+ <ClInclude Include="tridpars.h" />
+ <ClInclude Include="unesctrn.h" />
+ <ClInclude Include="uni2name.h" />
+ <CustomBuild Include="unicode\unirepl.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\utrans.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="csdetect.h" />
+ <ClInclude Include="csmatch.h" />
+ <ClInclude Include="csr2022.h" />
+ <ClInclude Include="csrecog.h" />
+ <ClInclude Include="csrmbcs.h" />
+ <ClInclude Include="csrsbcs.h" />
+ <ClInclude Include="csrucode.h" />
+ <ClInclude Include="csrutf8.h" />
+ <ClInclude Include="inputext.h" />
+ <CustomBuild Include="unicode\ucsdet.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="unicode\uspoof.h">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="uspoof_conf.h" />
+ <ClInclude Include="uspoof_impl.h" />
+ <ClInclude Include="uspoof_wsconf.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="i18n.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\common\common.vcxproj">
+ <Project>{73c0a65b-d1f2-4de1-b3a6-15dad2c23f3d}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj.filters b/Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj.filters
new file mode 100644
index 00000000000..ee3e3222af4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/i18n.vcxproj.filters
@@ -0,0 +1,1001 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="collation">
+ <UniqueIdentifier>{68f85997-0019-471f-b155-5eed0137f082}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="formatting">
+ <UniqueIdentifier>{8152306c-460d-49f3-961a-c500eda24e9d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="misc">
+ <UniqueIdentifier>{15349ca9-e31d-4f6b-a4c4-f73892fa5aa6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="regex">
+ <UniqueIdentifier>{faac495b-a9d6-47ad-ae47-a56c30c60b3a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="transforms">
+ <UniqueIdentifier>{e750fa6c-e471-4db0-92f9-81c84d84b5ba}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="charset detect">
+ <UniqueIdentifier>{59edb5a3-26d1-4c91-af50-4aa35e6e9730}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="spoof">
+ <UniqueIdentifier>{7b4a0782-fad3-44cd-b3b4-e75b0356d600}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="bms.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="bmsearch.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="bocsu.c">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="coleitr.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="coll.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="colldata.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="search.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="sortkey.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="stsearch.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="tblcoll.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_bld.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_cnt.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_elm.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_res.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_sit.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_tok.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucol_wgt.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="ucoleitr.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="usearch.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="astro.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="basictz.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="buddhcal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="calendar.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="cecal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="chnsecal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="choicfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="coptccal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="curramt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="currfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="currpinf.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="currunit.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="datefmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="dcfmtsym.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="decContext.c">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="decfmtst.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="decimfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="decNumber.c">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="digitlst.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="dtfmtsym.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="dtitvfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="dtitvinf.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="dtptngen.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="dtrule.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="ethpccal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="fmtable.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="fmtable_cnv.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="format.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="fphdlimp.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="fpositer.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="gregocal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="gregoimp.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="hebrwcal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="indiancal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="islamcal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="japancal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="locdspnm.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="measfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="measure.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="msgfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="nfrs.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="nfrule.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="nfsubs.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="numfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="numsys.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="olsontz.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="persncal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="plurfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="plurrule.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="rbnf.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="rbtz.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="reldtfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="selfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="simpletz.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="smpdtfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="smpdtfst.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="taiwncal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="timezone.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tmunit.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tmutamt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tmutfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tzrule.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tztrans.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="ucal.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="ucurr.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="udat.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="udateintervalformat.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="udatpg.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="ulocdata.c">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="umsg.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="unum.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="upluralrules.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="utmscale.c">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="vtzone.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="vzone.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="windtfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="winnmfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="wintzimpl.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="zonemeta.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="zrule.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="ztrans.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="ucln_in.c">
+ <Filter>misc</Filter>
+ </ClCompile>
+ <ClCompile Include="regexcmp.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="regexst.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="regextxt.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="rematch.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="repattrn.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="uregex.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="uregexc.cpp">
+ <Filter>regex</Filter>
+ </ClCompile>
+ <ClCompile Include="anytrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="brktrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="casetrn.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="cpdtrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="esctrn.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="funcrepl.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="name2uni.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="nortrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="nultrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="quant.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="rbt.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="rbt_data.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="rbt_pars.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="rbt_rule.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="rbt_set.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="remtrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="strmatch.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="strrepl.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="titletrn.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="tolowtrn.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="toupptrn.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="translit.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="transreg.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="tridpars.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="unesctrn.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="uni2name.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="utrans.cpp">
+ <Filter>transforms</Filter>
+ </ClCompile>
+ <ClCompile Include="csdetect.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csmatch.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csr2022.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csrecog.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csrmbcs.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csrsbcs.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csrucode.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="csrutf8.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="inputext.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="ucsdet.cpp">
+ <Filter>charset detect</Filter>
+ </ClCompile>
+ <ClCompile Include="uspoof.cpp">
+ <Filter>spoof</Filter>
+ </ClCompile>
+ <ClCompile Include="uspoof_build.cpp">
+ <Filter>spoof</Filter>
+ </ClCompile>
+ <ClCompile Include="uspoof_conf.cpp">
+ <Filter>spoof</Filter>
+ </ClCompile>
+ <ClCompile Include="uspoof_impl.cpp">
+ <Filter>spoof</Filter>
+ </ClCompile>
+ <ClCompile Include="uspoof_wsconf.cpp">
+ <Filter>spoof</Filter>
+ </ClCompile>
+ <ClCompile Include="alphaindex.cpp">
+ <Filter>collation</Filter>
+ </ClCompile>
+ <ClCompile Include="tzfmt.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tzgnames.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tznames.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ <ClCompile Include="tznames_impl.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="bocsu.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="ucol_bld.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="ucol_cnt.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="ucol_elm.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="ucol_imp.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="ucol_tok.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="ucol_wgt.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="usrchimp.h">
+ <Filter>collation</Filter>
+ </ClInclude>
+ <ClInclude Include="astro.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="buddhcal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="cecal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="chnsecal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="coptccal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="currfmt.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="decContext.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="decfmtst.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="decNumber.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="decNumberLocal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="digitlst.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="dtitv_impl.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="dtptngen_impl.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="ethpccal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="fphdlimp.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="gregoimp.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="hebrwcal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="indiancal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="islamcal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="japancal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="msgfmt_impl.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="nfrlist.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="nfrs.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="nfrule.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="nfsubs.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="olsontz.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="persncal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="plurrule_impl.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="reldtfmt.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="smpdtfst.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="taiwncal.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="ucurrimp.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="umsg_imp.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="vzone.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="windtfmt.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="winnmfmt.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="wintzimpl.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="zonemeta.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="zrule.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="ztrans.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="ucln_in.h">
+ <Filter>misc</Filter>
+ </ClInclude>
+ <ClInclude Include="regexcmp.h">
+ <Filter>regex</Filter>
+ </ClInclude>
+ <ClInclude Include="regexcst.h">
+ <Filter>regex</Filter>
+ </ClInclude>
+ <ClInclude Include="regeximp.h">
+ <Filter>regex</Filter>
+ </ClInclude>
+ <ClInclude Include="regexst.h">
+ <Filter>regex</Filter>
+ </ClInclude>
+ <ClInclude Include="regextxt.h">
+ <Filter>regex</Filter>
+ </ClInclude>
+ <ClInclude Include="anytrans.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="brktrans.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="casetrn.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="cpdtrans.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="esctrn.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="funcrepl.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="name2uni.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="nortrans.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="nultrans.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="quant.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="rbt.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="rbt_data.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="rbt_pars.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="rbt_rule.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="rbt_set.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="remtrans.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="strmatch.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="strrepl.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="titletrn.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="tolowtrn.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="toupptrn.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="transreg.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="tridpars.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="unesctrn.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="uni2name.h">
+ <Filter>transforms</Filter>
+ </ClInclude>
+ <ClInclude Include="csdetect.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csmatch.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csr2022.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csrecog.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csrmbcs.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csrsbcs.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csrucode.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="csrutf8.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="inputext.h">
+ <Filter>charset detect</Filter>
+ </ClInclude>
+ <ClInclude Include="uspoof_conf.h">
+ <Filter>spoof</Filter>
+ </ClInclude>
+ <ClInclude Include="uspoof_impl.h">
+ <Filter>spoof</Filter>
+ </ClInclude>
+ <ClInclude Include="uspoof_wsconf.h">
+ <Filter>spoof</Filter>
+ </ClInclude>
+ <ClInclude Include="tzfmt.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="tzgnames.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="tznames.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="tznames_impl.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="i18n.rc">
+ <Filter>misc</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="unicode\bms.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\bmsearch.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\coleitr.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\coll.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\colldata.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\search.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\sortkey.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\stsearch.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tblcoll.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucol.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucoleitr.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\usearch.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\basictz.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\calendar.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\choicfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\curramt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\currunit.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\datefmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dcfmtsym.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\decimfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtfmtsym.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtitvfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtitvinf.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtptngen.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\dtrule.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\fieldpos.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\fmtable.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\format.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\fpositer.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\gregocal.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\locdspnm.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\measfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\measunit.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\measure.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\msgfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\numfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\numsys.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\plurfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\plurrule.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\rbnf.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\rbtz.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\selfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\simpletz.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\smpdtfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\timezone.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tmunit.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tmutamt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tmutfmt.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tzrule.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\tztrans.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucal.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucurr.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\udat.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\udateintervalformat.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\udatpg.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\uldnames.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ulocdata.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\umsg.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\unum.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\upluralrules.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\utmscale.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\vtzone.h">
+ <Filter>formatting</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\regex.h">
+ <Filter>regex</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\uregex.h">
+ <Filter>regex</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\translit.h">
+ <Filter>transforms</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\unirepl.h">
+ <Filter>transforms</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\utrans.h">
+ <Filter>transforms</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\ucsdet.h">
+ <Filter>charset detect</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\uspoof.h">
+ <Filter>spoof</Filter>
+ </CustomBuild>
+ <CustomBuild Include="unicode\currpinf.h" />
+ <CustomBuild Include="unicode\alphaindex.h">
+ <Filter>collation</Filter>
+ </CustomBuild>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/indiancal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/indiancal.cpp
new file mode 100644
index 00000000000..526cfc44d2a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/indiancal.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2003-2009, 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
+ { -5000000, -5000000, 5000000, 5000000}, // YEAR
+ { 0, 0, 11, 11}, // MONTH
+ { 1, 1, 52, 53}, // WEEK_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // 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
+ { -5000000, -5000000, 5000000, 5000000}, // 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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
+};
+
+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 += ClockMath::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)ClockMath::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)
+
+ if (yday < INDIAN_YEAR_START) {
+ // Day is at the end of the preceding Saka year
+ IndianYear -= 1;
+ leapMonth = isGregorianLeap(gregorianYear - 1) ? 31 : 30; // Days in leapMonth this year, previous Gregorian year
+ yday += leapMonth + (31 * 5) + (30 * 3) + 10;
+ } else {
+ leapMonth = isGregorianLeap(gregorianYear) ? 31 : 30; // Days in leapMonth this year
+ 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);
+ internalSet(UCAL_DAY_OF_YEAR, yday + 1); // yday is 0-based
+}
+
+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-4.8.1/i18n/indiancal.h b/Build/source/libs/icu/icu-4.8.1/i18n/indiancal.h
new file mode 100644
index 00000000000..ff841fbfacb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/indiancal.h
@@ -0,0 +1,372 @@
+/*
+ *****************************************************************************
+ * Copyright (C) 2003-2008, 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 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
+ */
+ U_I18N_API 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-4.8.1/i18n/inputext.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/inputext.cpp
new file mode 100644
index 00000000000..e5a8ee1868a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/inputext.cpp
@@ -0,0 +1,164 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2009, 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(UErrorCode &status)
+ : 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)
+{
+ if (fInputBytes == NULL || fByteStats == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+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? (int32_t)uprv_strlen(in) : len;
+}
+
+void InputText::setDeclaredEncoding(const char* encoding, int32_t len)
+{
+ if(encoding) {
+ if (len == -1) {
+ len = (int32_t)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-4.8.1/i18n/inputext.h b/Build/source/libs/icu/icu-4.8.1/i18n/inputext.h
new file mode 100644
index 00000000000..0c5973d8eb2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/inputext.h
@@ -0,0 +1,61 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2008, 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
+{
+ // Prevent copying
+ InputText(const InputText &);
+public:
+ InputText(UErrorCode &status);
+ ~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-4.8.1/i18n/islamcal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/islamcal.cpp
new file mode 100644
index 00000000000..607d0a30ce6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/islamcal.cpp
@@ -0,0 +1,549 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2011, 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
+//-------------------------------------------------------------------------
+
+// Note: Current IslamicCalendar implementation does not work
+// well with negative years.
+
+// TODO: In some cases the current ICU Islamic calendar implementation shows
+// a month as having 31 days. Since date parsing now uses range checks based
+// on the table below, we need to change the range for last day of month to
+// include 31 as a workaround until the implementation is fixed.
+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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
+ { 1, 1, 29, 31}, // DAY_OF_MONTH - 31 to workaround for cal implementation bug, should be 30
+ { 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, 5000000, 5000000}, // 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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
+};
+
+/**
+* @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 + ClockMath::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)ClockMath::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) * kOneDay;
+
+ // moonAge will fail due to memory allocation error
+ double age = moonAge(origin, status);
+ if (U_FAILURE(status)) {
+ goto trueMonthStartEnd;
+ }
+
+ if (age >= 0) {
+ // The month has already started
+ do {
+ origin -= kOneDay;
+ age = moonAge(origin, status);
+ if (U_FAILURE(status)) {
+ goto trueMonthStartEnd;
+ }
+ } while (age >= 0);
+ }
+ else {
+ // Preceding month has not ended yet.
+ do {
+ origin += kOneDay;
+ age = moonAge(origin, status);
+ if (U_FAILURE(status)) {
+ goto trueMonthStartEnd;
+ }
+ } while (age < 0);
+ }
+ start = (int32_t)ClockMath::floorDivide((origin - HIJRA_MILLIS), (double)kOneDay) + 1;
+ CalendarCache::put(&gMonthCache, month, start, status);
+ }
+trueMonthStartEnd :
+ 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, UErrorCode &status)
+{
+ double age = 0;
+
+ umtx_lock(&astroLock);
+ if(gIslamicCalendarAstro == NULL) {
+ gIslamicCalendarAstro = new CalendarAstronomer();
+ if (gIslamicCalendarAstro == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return age;
+ }
+ ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup);
+ }
+ gIslamicCalendarAstro->setTime(time);
+ age = gIslamicCalendarAstro->getMoonAge();
+ 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)ClockMath::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);
+
+ double age = moonAge(internalGetTime(), status);
+ if (U_FAILURE(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if ( days - startDate >= 25 && age > 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()) == NULL && !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.
+ 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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ 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-4.8.1/i18n/islamcal.h b/Build/source/libs/icu/icu-4.8.1/i18n/islamcal.h
new file mode 100644
index 00000000000..e3647bc0ffd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/islamcal.h
@@ -0,0 +1,463 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2003-2009, 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 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, UErrorCode &status);
+
+ //-------------------------------------------------------------------------
+ // 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-4.8.1/i18n/japancal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/japancal.cpp
new file mode 100644
index 00000000000..ad95b7c04bc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/japancal.cpp
@@ -0,0 +1,531 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003-2009, 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]))
+
+/**
+ * The current era, for reference.
+ */
+static const int32_t kCurrentEra = (kEraCount-1); // int32_t to match the calendar field type
+
+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(int32_t eyear)
+{
+ int32_t era = internalGetEra();
+ // TODO do we assume we can trust 'era'? What if it is denormalized?
+
+ int32_t month = 0;
+
+ // Find out if we are at the edge of an era
+
+ if(eyear == 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 eyear, int32_t month)
+{
+ int32_t era = internalGetEra();
+ int32_t day = 1;
+
+ if(eyear == 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;
+}
+
+int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+ switch(field) {
+ case UCAL_ERA:
+ if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
+ return 1;
+ }
+ return kCurrentEra;
+ case UCAL_YEAR:
+ {
+ switch (limitType) {
+ case UCAL_LIMIT_MINIMUM:
+ case UCAL_LIMIT_GREATEST_MINIMUM:
+ return 1;
+ case UCAL_LIMIT_LEAST_MAXIMUM:
+ return 1;
+ case UCAL_LIMIT_COUNT: //added to avoid warning
+ case UCAL_LIMIT_MAXIMUM:
+ return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - kEraInfo[kCurrentEra].year;
+ default:
+ return 1; // Error condition, invalid limitType
+ }
+ }
+ default:
+ return GregorianCalendar::handleGetLimit(field,limitType);
+ }
+}
+
+int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const {
+ if (field == UCAL_YEAR) {
+ int32_t era = get(UCAL_ERA, status);
+ if (U_FAILURE(status)) {
+ return 0; // error case... any value
+ }
+ if (era == kCurrentEra) {
+ // TODO: Investigate what value should be used here - revisit after 4.0.
+ return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
+ } else {
+ int32_t nextEraYear = kEraInfo[era + 1].year;
+ int32_t nextEraMonth = kEraInfo[era + 1].month;
+ int32_t nextEraDate = kEraInfo[era + 1].day;
+
+ int32_t maxYear = nextEraYear - kEraInfo[era].year + 1; // 1-base
+ if (nextEraMonth == 1 && nextEraDate == 1) {
+ // Subtract 1, because the next era starts at Jan 1
+ maxYear--;
+ }
+ return maxYear;
+ }
+ }
+ return GregorianCalendar::getActualMaximum(field, status);
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/japancal.h b/Build/source/libs/icu/icu-4.8.1/i18n/japancal.h
new file mode 100644
index 00000000000..4219d6a5231
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/japancal.h
@@ -0,0 +1,217 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2003-2008, 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();
+
+ /**
+ * Return the maximum value that this field could have, given the current date.
+ * @internal
+ */
+ virtual int32_t getActualMaximum(UCalendarDateFields field, 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.
+ * @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.
+ * @param eyear the extended year
+ * @internal
+ */
+ virtual int32_t getDefaultMonthInYear(int32_t eyear);
+
+ /***
+ * 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.
+ * @param eyear the extended year
+ * @param mon the month in the year
+ * @internal
+ */
+ virtual int32_t getDefaultDayInMonth(int32_t eyear, int32_t month);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+//eof
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/locdspnm.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/locdspnm.cpp
new file mode 100644
index 00000000000..d4f4121cd15
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/locdspnm.cpp
@@ -0,0 +1,694 @@
+/*
+*******************************************************************************
+* Copyright (C) 2010-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/locdspnm.h"
+
+#include "unicode/msgfmt.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "ulocimp.h"
+#include "ureslocs.h"
+
+#include <stdarg.h>
+
+/**
+ * Concatenate a number of null-terminated strings to buffer, leaving a
+ * null-terminated string. The last argument should be the null pointer.
+ * Return the length of the string in the buffer, not counting the trailing
+ * null. Return -1 if there is an error (buffer is null, or buflen < 1).
+ */
+static int32_t ncat(char *buffer, uint32_t buflen, ...) {
+ va_list args;
+ char *str;
+ char *p = buffer;
+ const char* e = buffer + buflen - 1;
+
+ if (buffer == NULL || buflen < 1) {
+ return -1;
+ }
+
+ va_start(args, buflen);
+ while ((str = va_arg(args, char *))) {
+ char c;
+ while (p != e && (c = *str++)) {
+ *p++ = c;
+ }
+ }
+ *p = 0;
+ va_end(args);
+
+ return p - buffer;
+}
+
+U_NAMESPACE_BEGIN
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Access resource data for locale components.
+// Wrap code in uloc.c for now.
+class ICUDataTable {
+ const char* path;
+ Locale locale;
+
+public:
+ ICUDataTable(const char* path, const Locale& locale);
+ ~ICUDataTable();
+
+ const Locale& getLocale();
+
+ UnicodeString& get(const char* tableKey, const char* itemKey,
+ UnicodeString& result) const;
+ UnicodeString& get(const char* tableKey, const char* subTableKey, const char* itemKey,
+ UnicodeString& result) const;
+
+ UnicodeString& getNoFallback(const char* tableKey, const char* itemKey,
+ UnicodeString &result) const;
+ UnicodeString& getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey,
+ UnicodeString &result) const;
+};
+
+inline UnicodeString &
+ICUDataTable::get(const char* tableKey, const char* itemKey, UnicodeString& result) const {
+ return get(tableKey, NULL, itemKey, result);
+}
+
+inline UnicodeString &
+ICUDataTable::getNoFallback(const char* tableKey, const char* itemKey, UnicodeString& result) const {
+ return getNoFallback(tableKey, NULL, itemKey, result);
+}
+
+ICUDataTable::ICUDataTable(const char* path, const Locale& locale)
+ : path(NULL), locale(Locale::getRoot())
+{
+ if (path) {
+ int32_t len = uprv_strlen(path);
+ this->path = (const char*) uprv_malloc(len + 1);
+ if (this->path) {
+ uprv_strcpy((char *)this->path, path);
+ this->locale = locale;
+ }
+ }
+}
+
+ICUDataTable::~ICUDataTable() {
+ if (path) {
+ uprv_free((void*) path);
+ path = NULL;
+ }
+}
+
+const Locale&
+ICUDataTable::getLocale() {
+ return locale;
+}
+
+UnicodeString &
+ICUDataTable::get(const char* tableKey, const char* subTableKey, const char* itemKey,
+ UnicodeString &result) const {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = 0;
+
+ const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(),
+ tableKey, subTableKey, itemKey,
+ &len, &status);
+ if (U_SUCCESS(status)) {
+ return result.setTo(s, len);
+ }
+ return result.setTo(UnicodeString(itemKey, -1, US_INV));
+}
+
+UnicodeString &
+ICUDataTable::getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey,
+ UnicodeString& result) const {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = 0;
+
+ const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(),
+ tableKey, subTableKey, itemKey,
+ &len, &status);
+ if (U_SUCCESS(status)) {
+ return result.setTo(s, len);
+ }
+
+ result.setToBogus();
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(LocaleDisplayNames)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0 // currently unused
+
+class DefaultLocaleDisplayNames : public LocaleDisplayNames {
+ UDialectHandling dialectHandling;
+
+public:
+ // constructor
+ DefaultLocaleDisplayNames(UDialectHandling dialectHandling);
+
+ virtual ~DefaultLocaleDisplayNames();
+
+ virtual const Locale& getLocale() const;
+ virtual UDialectHandling getDialectHandling() const;
+ virtual UnicodeString& localeDisplayName(const Locale& locale,
+ UnicodeString& result) const;
+ virtual UnicodeString& localeDisplayName(const char* localeId,
+ UnicodeString& result) const;
+ virtual UnicodeString& languageDisplayName(const char* lang,
+ UnicodeString& result) const;
+ virtual UnicodeString& scriptDisplayName(const char* script,
+ UnicodeString& result) const;
+ virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
+ UnicodeString& result) const;
+ virtual UnicodeString& regionDisplayName(const char* region,
+ UnicodeString& result) const;
+ virtual UnicodeString& variantDisplayName(const char* variant,
+ UnicodeString& result) const;
+ virtual UnicodeString& keyDisplayName(const char* key,
+ UnicodeString& result) const;
+ virtual UnicodeString& keyValueDisplayName(const char* key,
+ const char* value,
+ UnicodeString& result) const;
+};
+
+DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling)
+ : dialectHandling(dialectHandling) {
+}
+
+DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() {
+}
+
+const Locale&
+DefaultLocaleDisplayNames::getLocale() const {
+ return Locale::getRoot();
+}
+
+UDialectHandling
+DefaultLocaleDisplayNames::getDialectHandling() const {
+ return dialectHandling;
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::localeDisplayName(const Locale& locale,
+ UnicodeString& result) const {
+ return result = UnicodeString(locale.getName(), -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::localeDisplayName(const char* localeId,
+ UnicodeString& result) const {
+ return result = UnicodeString(localeId, -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::languageDisplayName(const char* lang,
+ UnicodeString& result) const {
+ return result = UnicodeString(lang, -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::scriptDisplayName(const char* script,
+ UnicodeString& result) const {
+ return result = UnicodeString(script, -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode,
+ UnicodeString& result) const {
+ const char* name = uscript_getName(scriptCode);
+ if (name) {
+ return result = UnicodeString(name, -1, US_INV);
+ }
+ return result.remove();
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::regionDisplayName(const char* region,
+ UnicodeString& result) const {
+ return result = UnicodeString(region, -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::variantDisplayName(const char* variant,
+ UnicodeString& result) const {
+ return result = UnicodeString(variant, -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::keyDisplayName(const char* key,
+ UnicodeString& result) const {
+ return result = UnicodeString(key, -1, US_INV);
+}
+
+UnicodeString&
+DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */,
+ const char* value,
+ UnicodeString& result) const {
+ return result = UnicodeString(value, -1, US_INV);
+}
+
+#endif // currently unused class DefaultLocaleDisplayNames
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+class LocaleDisplayNamesImpl : public LocaleDisplayNames {
+ Locale locale;
+ UDialectHandling dialectHandling;
+ ICUDataTable langData;
+ ICUDataTable regionData;
+ UnicodeString sep;
+ MessageFormat *format;
+
+public:
+ // constructor
+ LocaleDisplayNamesImpl(const Locale& locale, UDialectHandling dialectHandling);
+ virtual ~LocaleDisplayNamesImpl();
+
+ virtual const Locale& getLocale() const;
+ virtual UDialectHandling getDialectHandling() const;
+
+ virtual UnicodeString& localeDisplayName(const Locale& locale,
+ UnicodeString& result) const;
+ virtual UnicodeString& localeDisplayName(const char* localeId,
+ UnicodeString& result) const;
+ virtual UnicodeString& languageDisplayName(const char* lang,
+ UnicodeString& result) const;
+ virtual UnicodeString& scriptDisplayName(const char* script,
+ UnicodeString& result) const;
+ virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
+ UnicodeString& result) const;
+ virtual UnicodeString& regionDisplayName(const char* region,
+ UnicodeString& result) const;
+ virtual UnicodeString& variantDisplayName(const char* variant,
+ UnicodeString& result) const;
+ virtual UnicodeString& keyDisplayName(const char* key,
+ UnicodeString& result) const;
+ virtual UnicodeString& keyValueDisplayName(const char* key,
+ const char* value,
+ UnicodeString& result) const;
+private:
+ UnicodeString& localeIdName(const char* localeId,
+ UnicodeString& result) const;
+ UnicodeString& appendWithSep(UnicodeString& buffer, const UnicodeString& src) const;
+};
+
+LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
+ UDialectHandling dialectHandling)
+ : dialectHandling(dialectHandling)
+ , langData(U_ICUDATA_LANG, locale)
+ , regionData(U_ICUDATA_REGION, locale)
+ , format(NULL)
+{
+ LocaleDisplayNamesImpl *nonConstThis = (LocaleDisplayNamesImpl *)this;
+ nonConstThis->locale = langData.getLocale() == Locale::getRoot()
+ ? regionData.getLocale()
+ : langData.getLocale();
+
+ langData.getNoFallback("localeDisplayPattern", "separator", sep);
+ if (sep.isBogus()) {
+ sep = UnicodeString(", ", -1, US_INV);
+ }
+
+ UnicodeString pattern;
+ langData.getNoFallback("localeDisplayPattern", "pattern", pattern);
+ if (pattern.isBogus()) {
+ pattern = UnicodeString("{0} ({1})", -1, US_INV);
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ format = new MessageFormat(pattern, status);
+}
+
+LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
+ delete format;
+}
+
+const Locale&
+LocaleDisplayNamesImpl::getLocale() const {
+ return locale;
+}
+
+UDialectHandling
+LocaleDisplayNamesImpl::getDialectHandling() const {
+ return dialectHandling;
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::localeDisplayName(const Locale& locale,
+ UnicodeString& result) const {
+ UnicodeString resultName;
+
+ const char* lang = locale.getLanguage();
+ if (uprv_strlen(lang) == 0) {
+ lang = "root";
+ }
+ const char* script = locale.getScript();
+ const char* country = locale.getCountry();
+ const char* variant = locale.getVariant();
+
+ UBool hasScript = uprv_strlen(script) > 0;
+ UBool hasCountry = uprv_strlen(country) > 0;
+ UBool hasVariant = uprv_strlen(variant) > 0;
+
+ if (dialectHandling == ULDN_DIALECT_NAMES) {
+ char buffer[ULOC_FULLNAME_CAPACITY];
+ do { // loop construct is so we can break early out of search
+ if (hasScript && hasCountry) {
+ ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, "_", country, (char *)0);
+ localeIdName(buffer, resultName);
+ if (!resultName.isBogus()) {
+ hasScript = FALSE;
+ hasCountry = FALSE;
+ break;
+ }
+ }
+ if (hasScript) {
+ ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, (char *)0);
+ localeIdName(buffer, resultName);
+ if (!resultName.isBogus()) {
+ hasScript = FALSE;
+ break;
+ }
+ }
+ if (hasCountry) {
+ ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", country, (char*)0);
+ localeIdName(buffer, resultName);
+ if (!resultName.isBogus()) {
+ hasCountry = FALSE;
+ break;
+ }
+ }
+ } while (FALSE);
+ }
+ if (resultName.isBogus() || resultName.isEmpty()) {
+ localeIdName(lang, resultName);
+ }
+
+ UnicodeString resultRemainder;
+ UnicodeString temp;
+ StringEnumeration *e = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (hasScript) {
+ resultRemainder.append(scriptDisplayName(script, temp));
+ }
+ if (hasCountry) {
+ appendWithSep(resultRemainder, regionDisplayName(country, temp));
+ }
+ if (hasVariant) {
+ appendWithSep(resultRemainder, variantDisplayName(variant, temp));
+ }
+
+ e = locale.createKeywords(status);
+ if (e && U_SUCCESS(status)) {
+ UnicodeString temp2;
+ char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; // sigh, no ULOC_VALUE_CAPACITY
+ const char* key;
+ while ((key = e->next((int32_t *)0, status)) != NULL) {
+ locale.getKeywordValue(key, value, ULOC_KEYWORD_AND_VALUES_CAPACITY, status);
+ appendWithSep(resultRemainder, keyDisplayName(key, temp))
+ .append((UChar)0x3d /* = */)
+ .append(keyValueDisplayName(key, value, temp2));
+ }
+ delete e;
+ }
+
+ if (!resultRemainder.isEmpty()) {
+ Formattable data[] = {
+ resultName,
+ resultRemainder
+ };
+ FieldPosition fpos;
+ status = U_ZERO_ERROR;
+ format->format(data, 2, result, fpos, status);
+ return result;
+ }
+
+ return result = resultName;
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::appendWithSep(UnicodeString& buffer, const UnicodeString& src) const {
+ if (!buffer.isEmpty()) {
+ buffer.append(sep);
+ }
+ buffer.append(src);
+ return buffer;
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::localeDisplayName(const char* localeId,
+ UnicodeString& result) const {
+ return localeDisplayName(Locale(localeId), result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::localeIdName(const char* localeId,
+ UnicodeString& result) const {
+ return langData.getNoFallback("Languages", localeId, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::languageDisplayName(const char* lang,
+ UnicodeString& result) const {
+ if (uprv_strcmp("root", lang) == 0 || uprv_strchr(lang, '_') != NULL) {
+ return result = UnicodeString(lang, -1, US_INV);
+ }
+ return langData.get("Languages", lang, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
+ UnicodeString& result) const {
+ return langData.get("Scripts", script, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode,
+ UnicodeString& result) const {
+ const char* name = uscript_getName(scriptCode);
+ return langData.get("Scripts", name, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::regionDisplayName(const char* region,
+ UnicodeString& result) const {
+ return regionData.get("Countries", region, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
+ UnicodeString& result) const {
+ return langData.get("Variants", variant, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::keyDisplayName(const char* key,
+ UnicodeString& result) const {
+ return langData.get("Keys", key, result);
+}
+
+UnicodeString&
+LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
+ const char* value,
+ UnicodeString& result) const {
+ return langData.get("Types", key, value, result);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+LocaleDisplayNames*
+LocaleDisplayNames::createInstance(const Locale& locale,
+ UDialectHandling dialectHandling) {
+ return new LocaleDisplayNamesImpl(locale, dialectHandling);
+}
+
+U_NAMESPACE_END
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+U_NAMESPACE_USE
+
+U_DRAFT ULocaleDisplayNames * U_EXPORT2
+uldn_open(const char * locale,
+ UDialectHandling dialectHandling,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (locale == NULL) {
+ locale = uloc_getDefault();
+ }
+ return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), dialectHandling);
+}
+
+U_DRAFT void U_EXPORT2
+uldn_close(ULocaleDisplayNames *ldn) {
+ delete (LocaleDisplayNames *)ldn;
+}
+
+U_DRAFT const char * U_EXPORT2
+uldn_getLocale(const ULocaleDisplayNames *ldn) {
+ if (ldn) {
+ return ((const LocaleDisplayNames *)ldn)->getLocale().getName();
+ }
+ return NULL;
+}
+
+U_DRAFT UDialectHandling U_EXPORT2
+uldn_getDialectHandling(const ULocaleDisplayNames *ldn) {
+ if (ldn) {
+ return ((const LocaleDisplayNames *)ldn)->getDialectHandling();
+ }
+ return ULDN_STANDARD_NAMES;
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_localeDisplayName(const ULocaleDisplayNames *ldn,
+ const char *locale,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || locale == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->localeDisplayName(locale, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_languageDisplayName(const ULocaleDisplayNames *ldn,
+ const char *lang,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || lang == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->languageDisplayName(lang, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_scriptDisplayName(const ULocaleDisplayNames *ldn,
+ const char *script,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || script == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->scriptDisplayName(script, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_scriptCodeDisplayName(const ULocaleDisplayNames *ldn,
+ UScriptCode scriptCode,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ return uldn_scriptDisplayName(ldn, uscript_getName(scriptCode), result, maxResultSize, pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_regionDisplayName(const ULocaleDisplayNames *ldn,
+ const char *region,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || region == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->regionDisplayName(region, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_variantDisplayName(const ULocaleDisplayNames *ldn,
+ const char *variant,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || variant == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->variantDisplayName(variant, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_keyDisplayName(const ULocaleDisplayNames *ldn,
+ const char *key,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || key == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->keyDisplayName(key, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uldn_keyValueDisplayName(const ULocaleDisplayNames *ldn,
+ const char *key,
+ const char *value,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if (ldn == NULL || key == NULL || value == NULL || (result == NULL && maxResultSize > 0)
+ || maxResultSize < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString temp(result, 0, maxResultSize);
+ ((const LocaleDisplayNames *)ldn)->keyValueDisplayName(key, value, temp);
+ return temp.extract(result, maxResultSize, *pErrorCode);
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/measfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/measfmt.cpp
new file mode 100644
index 00000000000..eaa37a24850
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/measure.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/measure.cpp
new file mode 100644
index 00000000000..7b91677a3c0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/measure.cpp
@@ -0,0 +1,67 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include <typeinfo> // for 'typeid' to work
+
+#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 typeid(*this) == typeid(other) &&
+ number == m->getNumber() &&
+ (unit != NULL && *unit == m->getUnit());
+}
+
+//----------------------------------------------------------------------
+// MeasureUnit implementation
+
+MeasureUnit:: MeasureUnit() {}
+
+MeasureUnit::~MeasureUnit() {}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/msgfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/msgfmt.cpp
new file mode 100644
index 00000000000..a064c5d0911
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/msgfmt.cpp
@@ -0,0 +1,1805 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2011, 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
+ * 11/01/09 kirtig Added SelectFormat
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/appendable.h"
+#include "unicode/choicfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/localpointer.h"
+#include "unicode/msgfmt.h"
+#include "unicode/plurfmt.h"
+#include "unicode/rbnf.h"
+#include "unicode/selfmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/umsg.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "patternprops.h"
+#include "messageimpl.h"
+#include "msgfmt_impl.h"
+#include "uassert.h"
+#include "ustrfmt.h"
+#include "util.h"
+#include "uvector.h"
+
+// *****************************************************************************
+// class MessageFormat
+// *****************************************************************************
+
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define COMMA ((UChar)0x002C)
+#define LEFT_CURLY_BRACE ((UChar)0x007B)
+#define RIGHT_CURLY_BRACE ((UChar)0x007D)
+
+//---------------------------------------
+// static data
+
+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_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_NUMBER,
+ ID_DATE,
+ ID_TIME,
+ ID_SPELLOUT,
+ ID_ORDINAL,
+ ID_DURATION,
+ NULL,
+};
+
+static const UChar ID_EMPTY[] = {
+ 0 /* empty string, used for default so that null can mark end of list */
+};
+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;
+
+static const UChar NULL_STRING[] = {
+ 0x6E, 0x75, 0x6C, 0x6C, 0 // "null"
+};
+
+static const UChar OTHER_STRING[] = {
+ 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other"
+};
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV equalFormatsForHash(const UHashTok key1,
+ const UHashTok key2) {
+ return U_NAMESPACE_QUALIFIER MessageFormat::equalFormats(key1.pointer, key2.pointer);
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
+UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(MessageFormat::DummyFormat)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration)
+
+//--------------------------------------------------------------------
+
+/**
+ * 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;
+}
+
+
+// AppendableWrapper: encapsulates the result of formatting, keeping track
+// of the string and its length.
+class AppendableWrapper : public UMemory {
+public:
+ AppendableWrapper(Appendable& appendable) : app(appendable), len(0) {
+ }
+ void append(const UnicodeString& s) {
+ app.appendString(s.getBuffer(), s.length());
+ len += s.length();
+ }
+ void append(const UChar* s, const int32_t sLength) {
+ app.appendString(s, sLength);
+ len += sLength;
+ }
+ void append(const UnicodeString& s, int32_t start, int32_t length) {
+ append(s.tempSubString(start, length));
+ }
+ void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) {
+ UnicodeString s;
+ formatter->format(arg, s, ec);
+ if (U_SUCCESS(ec)) {
+ append(s);
+ }
+ }
+ int32_t length() {
+ return len;
+ }
+private:
+ Appendable& app;
+ int32_t len;
+};
+
+
+// -------------------------------------
+// Creates a MessageFormat instance based on the pattern.
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ UErrorCode& success)
+: fLocale(Locale::getDefault()), // Uses the default locale
+ msgPattern(success),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ hasArgTypeConflicts(FALSE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL),
+ cachedFormatters(NULL),
+ customFormatArgStarts(NULL),
+ pluralProvider(&fLocale)
+{
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+ applyPattern(pattern, success);
+}
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UErrorCode& success)
+: fLocale(newLocale),
+ msgPattern(success),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ hasArgTypeConflicts(FALSE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL),
+ cachedFormatters(NULL),
+ customFormatArgStarts(NULL),
+ pluralProvider(&fLocale)
+{
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+ applyPattern(pattern, success);
+}
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UParseError& parseError,
+ UErrorCode& success)
+: fLocale(newLocale),
+ msgPattern(success),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ hasArgTypeConflicts(FALSE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL),
+ cachedFormatters(NULL),
+ customFormatArgStarts(NULL),
+ pluralProvider(&fLocale)
+{
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+ applyPattern(pattern, parseError, success);
+}
+
+MessageFormat::MessageFormat(const MessageFormat& that)
+:
+ Format(that),
+ fLocale(that.fLocale),
+ msgPattern(that.msgPattern),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ hasArgTypeConflicts(that.hasArgTypeConflicts),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL),
+ cachedFormatters(NULL),
+ customFormatArgStarts(NULL),
+ pluralProvider(&fLocale)
+{
+ // This will take care of creating the hash tables (since they are NULL).
+ UErrorCode ec = U_ZERO_ERROR;
+ copyObjects(that, ec);
+ if (U_FAILURE(ec)) {
+ resetPattern();
+ }
+}
+
+MessageFormat::~MessageFormat()
+{
+ uhash_close(cachedFormatters);
+ uhash_close(customFormatArgStarts);
+
+ uprv_free(argTypes);
+ uprv_free(formatAliases);
+ delete defaultNumberFormat;
+ delete defaultDateFormat;
+}
+
+//--------------------------------------------------------------------
+// Variable-size array management
+
+/**
+ * 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, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (argTypeCapacity >= capacity) {
+ return TRUE;
+ }
+ if (capacity < DEFAULT_INITIAL_CAPACITY) {
+ capacity = DEFAULT_INITIAL_CAPACITY;
+ } else if (capacity < 2*argTypeCapacity) {
+ capacity = 2*argTypeCapacity;
+ }
+ Formattable::Type* a = (Formattable::Type*)
+ uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
+ if (a == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ argTypes = a;
+ argTypeCapacity = capacity;
+ return TRUE;
+}
+
+// -------------------------------------
+// assignment operator
+
+const MessageFormat&
+MessageFormat::operator=(const MessageFormat& that)
+{
+ if (this != &that) {
+ // Calls the super class for assignment first.
+ Format::operator=(that);
+
+ setLocale(that.fLocale);
+ msgPattern = that.msgPattern;
+ hasArgTypeConflicts = that.hasArgTypeConflicts;
+
+ UErrorCode ec = U_ZERO_ERROR;
+ copyObjects(that, ec);
+ if (U_FAILURE(ec)) {
+ resetPattern();
+ }
+ }
+ 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) ||
+ msgPattern != that.msgPattern ||
+ fLocale != that.fLocale) {
+ return FALSE;
+ }
+
+ // Compare hashtables.
+ if ((customFormatArgStarts == NULL) != (that.customFormatArgStarts == NULL)) {
+ return FALSE;
+ }
+ if (customFormatArgStarts == NULL) {
+ return TRUE;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ const int32_t count = uhash_count(customFormatArgStarts);
+ const int32_t rhs_count = uhash_count(that.customFormatArgStarts);
+ if (count != rhs_count) {
+ return FALSE;
+ }
+ int idx = 0, rhs_idx = 0, pos = -1, rhs_pos = -1;
+ for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) {
+ const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos);
+ const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos);
+ if (cur->key.integer != rhs_cur->key.integer) {
+ return FALSE;
+ }
+ const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer);
+ const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer);
+ if (*format != *rhs_format) {
+ 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());
+ pluralProvider.reset(&fLocale);
+ }
+}
+
+// -------------------------------------
+// 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;
+ }
+ msgPattern.parse(pattern, &parseError, ec);
+ cacheExplicitFormats(ec);
+
+ if (U_FAILURE(ec)) {
+ resetPattern();
+ }
+}
+
+void MessageFormat::resetPattern() {
+ msgPattern.clear();
+ uhash_close(cachedFormatters);
+ cachedFormatters = NULL;
+ uhash_close(customFormatArgStarts);
+ customFormatArgStarts = NULL;
+ argTypeCount = 0;
+ hasArgTypeConflicts = FALSE;
+}
+
+void
+MessageFormat::applyPattern(const UnicodeString& pattern,
+ UMessagePatternApostropheMode aposMode,
+ UParseError* parseError,
+ UErrorCode& status) {
+ if (aposMode != msgPattern.getApostropheMode()) {
+ msgPattern.clearPatternAndSetApostropheMode(aposMode);
+ }
+ applyPattern(pattern, *parseError, status);
+}
+
+// -------------------------------------
+// Converts this MessageFormat instance to a pattern.
+
+UnicodeString&
+MessageFormat::toPattern(UnicodeString& appendTo) const {
+ if ((customFormatArgStarts != NULL && 0 != uhash_count(customFormatArgStarts)) ||
+ 0 == msgPattern.countParts()
+ ) {
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ return appendTo.append(msgPattern.getPatternString());
+}
+
+int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
+ if (partIndex != 0) {
+ partIndex = msgPattern.getLimitPartIndex(partIndex);
+ }
+ for (;;) {
+ UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
+ if (type == UMSGPAT_PART_TYPE_ARG_START) {
+ return partIndex;
+ }
+ if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
+ return -1;
+ }
+ }
+}
+
+void MessageFormat::setArgStartFormat(int32_t argStart,
+ Format* formatter,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ delete formatter;
+ }
+ if (cachedFormatters == NULL) {
+ cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
+ equalFormatsForHash, &status);
+ if (U_FAILURE(status)) {
+ delete formatter;
+ return;
+ }
+ uhash_setValueDeleter(cachedFormatters, uhash_deleteUObject);
+ }
+ if (formatter == NULL) {
+ formatter = new DummyFormat();
+ }
+ uhash_iput(cachedFormatters, argStart, formatter, &status);
+}
+
+
+UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
+ const MessagePattern::Part& part = msgPattern.getPart(partIndex);
+ return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
+ msgPattern.partSubstringMatches(part, argName) :
+ part.getValue() == argNumber; // ARG_NUMBER
+}
+
+// Sets a custom formatter for a MessagePattern ARG_START part index.
+// "Custom" formatters are provided by the user via setFormat() or similar APIs.
+void MessageFormat::setCustomArgStartFormat(int32_t argStart,
+ Format* formatter,
+ UErrorCode& status) {
+ setArgStartFormat(argStart, formatter, status);
+ if (customFormatArgStarts == NULL) {
+ customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
+ NULL, &status);
+ }
+ uhash_iputi(customFormatArgStarts, argStart, 1, &status);
+}
+
+Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
+ if (cachedFormatters == NULL) {
+ return NULL;
+ }
+ void* ptr = uhash_iget(cachedFormatters, argumentNumber);
+ if (ptr != NULL && dynamic_cast<DummyFormat*>((Format*)ptr) == NULL) {
+ return (Format*) ptr;
+ } else {
+ // Not cached, or a DummyFormat representing setFormat(NULL).
+ return NULL;
+ }
+}
+
+// -------------------------------------
+// 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;
+ }
+ // Throw away any cached formatters.
+ if (cachedFormatters != NULL) {
+ uhash_removeAll(cachedFormatters);
+ }
+ if (customFormatArgStarts != NULL) {
+ uhash_removeAll(customFormatArgStarts);
+ }
+
+ int32_t formatNumber = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ for (int32_t partIndex = 0;
+ formatNumber < count && U_SUCCESS(status) &&
+ (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
+ ++formatNumber;
+ }
+ // Delete those that didn't get used (if any).
+ for (; formatNumber < count; ++formatNumber) {
+ delete newFormats[formatNumber];
+ }
+
+}
+
+// -------------------------------------
+// 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;
+ }
+ // Throw away any cached formatters.
+ if (cachedFormatters != NULL) {
+ uhash_removeAll(cachedFormatters);
+ }
+ if (customFormatArgStarts != NULL) {
+ uhash_removeAll(customFormatArgStarts);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t formatNumber = 0;
+ for (int32_t partIndex = 0;
+ formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ Format* newFormat = NULL;
+ if (newFormats[formatNumber] != NULL) {
+ newFormat = newFormats[formatNumber]->clone();
+ if (newFormat == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ setCustomArgStartFormat(partIndex, newFormat, status);
+ ++formatNumber;
+ }
+ if (U_FAILURE(status)) {
+ resetPattern();
+ }
+}
+
+// -------------------------------------
+// Adopt a single format by format number.
+// Do nothing if the format number is not less than the array count.
+
+void
+MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
+ LocalPointer<Format> p(newFormat);
+ if (n >= 0) {
+ int32_t formatNumber = 0;
+ for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ if (n == formatNumber) {
+ UErrorCode status = U_ZERO_ERROR;
+ setCustomArgStartFormat(partIndex, p.orphan(), status);
+ return;
+ }
+ ++formatNumber;
+ }
+ }
+}
+
+// -------------------------------------
+// Adopt a single format by format name.
+// Do nothing if there is no match of formatName.
+void
+MessageFormat::adoptFormat(const UnicodeString& formatName,
+ Format* formatToAdopt,
+ UErrorCode& status) {
+ LocalPointer<Format> p(formatToAdopt);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int32_t argNumber = MessagePattern::validateArgumentName(formatName);
+ if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ for (int32_t partIndex = 0;
+ (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
+ ) {
+ if (argNameMatches(partIndex + 1, formatName, argNumber)) {
+ Format* f;
+ if (p.isValid()) {
+ f = p.orphan();
+ } else if (formatToAdopt == NULL) {
+ f = NULL;
+ } else {
+ f = formatToAdopt->clone();
+ if (f == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ setCustomArgStartFormat(partIndex, f, status);
+ }
+ }
+}
+
+// -------------------------------------
+// Set a single format.
+// Do nothing if the variable is not less than the array count.
+void
+MessageFormat::setFormat(int32_t n, const Format& newFormat) {
+
+ if (n >= 0) {
+ int32_t formatNumber = 0;
+ for (int32_t partIndex = 0;
+ (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ if (n == formatNumber) {
+ Format* new_format = newFormat.clone();
+ if (new_format) {
+ UErrorCode status = U_ZERO_ERROR;
+ setCustomArgStartFormat(partIndex, new_format, status);
+ }
+ return;
+ }
+ ++formatNumber;
+ }
+ }
+}
+
+// -------------------------------------
+// Get a single format by format name.
+// Do nothing if the variable is not less than the array count.
+Format *
+MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
+ if (U_FAILURE(status) || cachedFormatters == NULL) return NULL;
+
+ int32_t argNumber = MessagePattern::validateArgumentName(formatName);
+ if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ if (argNameMatches(partIndex + 1, formatName, argNumber)) {
+ return getCachedFormatter(partIndex);
+ }
+ }
+ return NULL;
+}
+
+// -------------------------------------
+// Set a single format by format name
+// Do nothing if the variable is not less than the array count.
+void
+MessageFormat::setFormat(const UnicodeString& formatName,
+ const Format& newFormat,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) return;
+
+ int32_t argNumber = MessagePattern::validateArgumentName(formatName);
+ if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ for (int32_t partIndex = 0;
+ (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
+ ) {
+ if (argNameMatches(partIndex + 1, formatName, argNumber)) {
+ if (&newFormat == NULL) {
+ setCustomArgStartFormat(partIndex, NULL, status);
+ } else {
+ Format* new_format = newFormat.clone();
+ if (new_format == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ setCustomArgStartFormat(partIndex, new_format, status);
+ }
+ }
+ }
+}
+
+// -------------------------------------
+// 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 = const_cast<MessageFormat*> (this);
+ cnt = 0;
+ if (formatAliases == NULL) {
+ t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount;
+ Format** a = (Format**)
+ uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
+ if (a == NULL) {
+ t->formatAliasesCapacity = 0;
+ return NULL;
+ }
+ t->formatAliases = a;
+ } else if (argTypeCount > formatAliasesCapacity) {
+ Format** a = (Format**)
+ uprv_realloc(formatAliases, sizeof(Format*) * argTypeCount);
+ if (a == NULL) {
+ t->formatAliasesCapacity = 0;
+ return NULL;
+ }
+ t->formatAliases = a;
+ t->formatAliasesCapacity = argTypeCount;
+ }
+
+ for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ t->formatAliases[cnt++] = getCachedFormatter(partIndex);
+ }
+
+ return (const Format**)formatAliases;
+}
+
+
+UnicodeString MessageFormat::getArgName(int32_t partIndex) {
+ const MessagePattern::Part& part = msgPattern.getPart(partIndex);
+ if (part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) {
+ return msgPattern.getSubstring(part);
+ } else {
+ UnicodeString temp;
+ return itos(part.getValue(), temp);
+ }
+}
+
+StringEnumeration*
+MessageFormat::getFormatNames(UErrorCode& status) {
+ if (U_FAILURE(status)) return NULL;
+
+ UVector *fFormatNames = new UVector(status);
+ if (U_FAILURE(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ fFormatNames->setDeleter(uhash_deleteUObject);
+
+ for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
+ fFormatNames->addElement(new UnicodeString(getArgName(partIndex)), status);
+ }
+
+ StringEnumeration* nameEnumerator = new FormatNameEnumeration(fFormatNames, status);
+ return nameEnumerator;
+}
+
+// -------------------------------------
+// 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
+{
+ return format(source, NULL, cnt, appendTo, &ignore, 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);
+ return temp.format(arguments, NULL, cnt, appendTo, NULL, success);
+}
+
+// -------------------------------------
+// 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
+{
+ if (U_FAILURE(success))
+ return appendTo;
+ if (source.getType() != Formattable::kArray) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+ int32_t cnt;
+ const Formattable* tmpPtr = source.getArray(cnt);
+ return format(tmpPtr, NULL, cnt, appendTo, &ignore, success);
+}
+
+UnicodeString&
+MessageFormat::format(const UnicodeString* argumentNames,
+ const Formattable* arguments,
+ int32_t count,
+ UnicodeString& appendTo,
+ UErrorCode& success) const {
+ return format(arguments, argumentNames, count, appendTo, NULL, success);
+}
+
+// Does linear search to find the match for an ArgName.
+const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt, UnicodeString& name) const {
+ for (int32_t i = 0; i < cnt; ++i) {
+ if (0 == argumentNames[i].compare(name)) {
+ return arguments + i;
+ }
+ }
+ return NULL;
+}
+
+
+UnicodeString&
+MessageFormat::format(const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition* pos,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+
+ UnicodeStringAppendable usapp(appendTo);
+ AppendableWrapper app(usapp);
+ format(0, 0.0, arguments, argumentNames, cnt, app, pos, status);
+ return appendTo;
+}
+
+// if argumentNames is NULL, this means arguments is a numeric array.
+// arguments can not be NULL.
+void MessageFormat::format(int32_t msgStart, double pluralNumber,
+ const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ AppendableWrapper& appendTo,
+ FieldPosition* ignore,
+ UErrorCode& success) const {
+ if (U_FAILURE(success)) {
+ return;
+ }
+
+ const UnicodeString& msgString = msgPattern.getPatternString();
+ int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
+ for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
+ const MessagePattern::Part* part = &msgPattern.getPart(i);
+ const UMessagePatternPartType type = part->getType();
+ int32_t index = part->getIndex();
+ appendTo.append(msgString, prevIndex, index - prevIndex);
+ if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
+ return;
+ }
+ prevIndex = part->getLimit();
+ if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
+ const NumberFormat* nf = getDefaultNumberFormat(success);
+ appendTo.formatAndAppend(nf, Formattable(pluralNumber), success);
+ continue;
+ }
+ if (type != UMSGPAT_PART_TYPE_ARG_START) {
+ continue;
+ }
+ int32_t argLimit = msgPattern.getLimitPartIndex(i);
+ UMessagePatternArgType argType = part->getArgType();
+ part = &msgPattern.getPart(++i);
+ const Formattable* arg;
+ UnicodeString noArg;
+ if (argumentNames == NULL) {
+ int32_t argNumber = part->getValue(); // ARG_NUMBER
+ if (0 <= argNumber && argNumber < cnt) {
+ arg = arguments + argNumber;
+ } else {
+ arg = NULL;
+ noArg.append(LEFT_CURLY_BRACE);
+ itos(argNumber, noArg);
+ noArg.append(RIGHT_CURLY_BRACE);
+ }
+ } else {
+ UnicodeString key;
+ if (part->getType() == UMSGPAT_PART_TYPE_ARG_NAME) {
+ key = msgPattern.getSubstring(*part);
+ } else /* UMSGPAT_PART_TYPE_ARG_NUMBER */ {
+ itos(part->getValue(), key);
+ }
+ arg = getArgFromListByName(arguments, argumentNames, cnt, key);
+ if (arg == NULL) {
+ noArg.append(LEFT_CURLY_BRACE);
+ noArg.append(key);
+ noArg.append(RIGHT_CURLY_BRACE);
+ }
+ }
+ ++i;
+ int32_t prevDestLength = appendTo.length();
+ const Format* formatter = NULL;
+ if (!noArg.isEmpty()) {
+ appendTo.append(noArg);
+ } else if (arg == NULL) {
+ appendTo.append(NULL_STRING, 4);
+ } else if ((formatter = getCachedFormatter(i -2))) {
+ // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
+ if (dynamic_cast<const ChoiceFormat*>(formatter) ||
+ dynamic_cast<const PluralFormat*>(formatter) ||
+ dynamic_cast<const SelectFormat*>(formatter)) {
+ // We only handle nested formats here if they were provided via
+ // setFormat() or its siblings. Otherwise they are not cached and instead
+ // handled below according to argType.
+ UnicodeString subMsgString;
+ formatter->format(*arg, subMsgString, success);
+ if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
+ (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
+ ) {
+ MessageFormat subMsgFormat(subMsgString, fLocale, success);
+ subMsgFormat.format(0, 0, arguments, argumentNames, cnt, appendTo, ignore, success);
+ } else {
+ appendTo.append(subMsgString);
+ }
+ } else {
+ appendTo.formatAndAppend(formatter, *arg, success);
+ }
+ } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) {
+ // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
+ // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
+ // for the hash table containind DummyFormat.
+ if (arg->isNumeric()) {
+ const NumberFormat* nf = getDefaultNumberFormat(success);
+ appendTo.formatAndAppend(nf, *arg, success);
+ } else if (arg->getType() == Formattable::kDate) {
+ const DateFormat* df = getDefaultDateFormat(success);
+ appendTo.formatAndAppend(df, *arg, success);
+ } else {
+ appendTo.append(arg->getString(success));
+ }
+ } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
+ if (!arg->isNumeric()) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ // We must use the Formattable::getDouble() variant with the UErrorCode parameter
+ // because only this one converts non-double numeric types to double.
+ const double number = arg->getDouble(success);
+ int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
+ formatComplexSubMessage(subMsgStart, 0, arguments, argumentNames,
+ cnt, appendTo, success);
+ } else if (argType == UMSGPAT_ARG_TYPE_PLURAL) {
+ if (!arg->isNumeric()) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ // We must use the Formattable::getDouble() variant with the UErrorCode parameter
+ // because only this one converts non-double numeric types to double.
+ double number = arg->getDouble(success);
+ int32_t subMsgStart = PluralFormat::findSubMessage(msgPattern, i, pluralProvider, number,
+ success);
+ double offset = msgPattern.getPluralOffset(subMsgStart);
+ formatComplexSubMessage(subMsgStart, number-offset, arguments, argumentNames,
+ cnt, appendTo, success);
+ } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
+ int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
+ formatComplexSubMessage(subMsgStart, 0, arguments, argumentNames,
+ cnt, appendTo, success);
+ } else {
+ // This should never happen.
+ success = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
+ prevIndex = msgPattern.getPart(argLimit).getLimit();
+ i = argLimit;
+ }
+}
+
+
+void MessageFormat::formatComplexSubMessage(int32_t msgStart,
+ double pluralNumber,
+ const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ AppendableWrapper& appendTo,
+ UErrorCode& success) const {
+ if (U_FAILURE(success)) {
+ return;
+ }
+
+ if (!MessageImpl::jdkAposMode(msgPattern)) {
+ format(msgStart, pluralNumber, arguments, argumentNames, cnt, appendTo, NULL, success);
+ return;
+ }
+
+ // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
+ // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
+ // - if the result string contains an open curly brace '{' then
+ // instantiate a temporary MessageFormat object and format again;
+ // otherwise just append the result string
+ const UnicodeString& msgString = msgPattern.getPatternString();
+ UnicodeString sb;
+ int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
+ for (int32_t i = msgStart;;) {
+ const MessagePattern::Part& part = msgPattern.getPart(++i);
+ const UMessagePatternPartType type = part.getType();
+ int32_t index = part.getIndex();
+ if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
+ sb.append(msgString, prevIndex, index - prevIndex);
+ break;
+ } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
+ sb.append(msgString, prevIndex, index - prevIndex);
+ if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
+ const NumberFormat* nf = getDefaultNumberFormat(success);
+ sb.append(nf->format(pluralNumber, sb, success));
+ }
+ prevIndex = part.getLimit();
+ } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
+ sb.append(msgString, prevIndex, index - prevIndex);
+ prevIndex = index;
+ i = msgPattern.getLimitPartIndex(i);
+ index = msgPattern.getPart(i).getLimit();
+ MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
+ prevIndex = index;
+ }
+ }
+ if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
+ UnicodeString emptyPattern; // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
+ MessageFormat subMsgFormat(emptyPattern, fLocale, success);
+ subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, success);
+ subMsgFormat.format(0, 0, arguments, argumentNames, cnt, appendTo, NULL, success);
+ } else {
+ appendTo.append(sb);
+ }
+}
+
+
+UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
+ const UnicodeString& msgString=msgPattern.getPatternString();
+ int32_t prevIndex=msgPattern.getPart(from).getLimit();
+ UnicodeString b;
+ for (int32_t i = from + 1; ; ++i) {
+ const MessagePattern::Part& part = msgPattern.getPart(i);
+ const UMessagePatternPartType type=part.getType();
+ int32_t index=part.getIndex();
+ b.append(msgString, prevIndex, index - prevIndex);
+ if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
+ return b;
+ }
+ // Unexpected Part "part" in parsed message.
+ U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
+ prevIndex=part.getLimit();
+ }
+}
+
+
+FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
+ FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
+ // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
+ return NULL;
+ /*
+ if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
+ fp->setBeginIndex(prevLength);
+ fp->setEndIndex(dest.get_length());
+ return NULL;
+ }
+ return fp;
+ */
+}
+
+void MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) {
+ // Deep copy pointer fields.
+ // We need not copy the formatAliases because they are re-filled
+ // in each getFormats() call.
+ // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
+ // also get created on demand.
+ argTypeCount = that.argTypeCount;
+ if (argTypeCount > 0) {
+ if (!allocateArgTypes(argTypeCount, ec)) {
+ return;
+ }
+ uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
+ }
+ if (cachedFormatters != NULL) {
+ uhash_removeAll(cachedFormatters);
+ }
+ if (customFormatArgStarts != NULL) {
+ uhash_removeAll(customFormatArgStarts);
+ }
+ if (that.cachedFormatters) {
+ if (cachedFormatters == NULL) {
+ cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
+ equalFormatsForHash, &ec);
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ uhash_setValueDeleter(cachedFormatters, uhash_deleteUObject);
+ }
+
+ const int32_t count = uhash_count(that.cachedFormatters);
+ int32_t pos, idx;
+ for (idx = 0, pos = -1; idx < count && U_SUCCESS(ec); ++idx) {
+ const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
+ Format* newFormat = ((Format*)(cur->value.pointer))->clone();
+ if (newFormat) {
+ uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
+ } else {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ }
+ if (that.customFormatArgStarts) {
+ if (customFormatArgStarts == NULL) {
+ customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
+ NULL, &ec);
+ }
+ const int32_t count = uhash_count(that.customFormatArgStarts);
+ int32_t pos, idx;
+ for (idx = 0, pos = -1; idx < count && U_SUCCESS(ec); ++idx) {
+ const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
+ uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
+ }
+ }
+}
+
+
+Formattable*
+MessageFormat::parse(int32_t msgStart,
+ const UnicodeString& source,
+ ParsePosition& pos,
+ int32_t& count,
+ UErrorCode& ec) const {
+ count = 0;
+ if (U_FAILURE(ec)) {
+ pos.setErrorIndex(pos.getIndex());
+ return NULL;
+ }
+ // parse() does not work with named arguments.
+ if (msgPattern.hasNamedArguments()) {
+ ec = U_ARGUMENT_TYPE_MISMATCH;
+ pos.setErrorIndex(pos.getIndex());
+ return NULL;
+ }
+ LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
+ const UnicodeString& msgString=msgPattern.getPatternString();
+ int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
+ int32_t sourceOffset = pos.getIndex();
+ ParsePosition tempStatus(0);
+
+ for(int32_t i=msgStart+1; ; ++i) {
+ UBool haveArgResult = FALSE;
+ const MessagePattern::Part* part=&msgPattern.getPart(i);
+ const UMessagePatternPartType type=part->getType();
+ int32_t index=part->getIndex();
+ // Make sure the literal string matches.
+ int32_t len = index - prevIndex;
+ if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
+ sourceOffset += len;
+ prevIndex += len;
+ } else {
+ pos.setErrorIndex(sourceOffset);
+ return NULL; // leave index as is to signal error
+ }
+ if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
+ // Things went well! Done.
+ pos.setIndex(sourceOffset);
+ return resultArray.orphan();
+ }
+ if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
+ prevIndex=part->getLimit();
+ continue;
+ }
+ // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
+ // Unexpected Part "part" in parsed message.
+ U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
+ int32_t argLimit=msgPattern.getLimitPartIndex(i);
+
+ UMessagePatternArgType argType=part->getArgType();
+ part=&msgPattern.getPart(++i);
+ int32_t argNumber = part->getValue(); // ARG_NUMBER
+ UnicodeString key;
+ ++i;
+ const Format* formatter = NULL;
+ Formattable& argResult = resultArray[argNumber];
+
+ if(cachedFormatters!=NULL && (formatter = getCachedFormatter(i - 2))!=NULL) {
+ // Just parse using the formatter.
+ tempStatus.setIndex(sourceOffset);
+ formatter->parseObject(source, argResult, tempStatus);
+ if (tempStatus.getIndex() == sourceOffset) {
+ pos.setErrorIndex(sourceOffset);
+ return NULL; // leave index as is to signal error
+ }
+ sourceOffset = tempStatus.getIndex();
+ haveArgResult = TRUE;
+ } else if(
+ argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) {
+ // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
+ // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
+ // for the hash table containind DummyFormat.
+
+ // Match as a string.
+ // if at end, use longest possible match
+ // otherwise uses first match to intervening string
+ // does NOT recursively try all possibilities
+ UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
+ int32_t next;
+ if (!stringAfterArgument.isEmpty()) {
+ next = source.indexOf(stringAfterArgument, sourceOffset);
+ } else {
+ next = source.length();
+ }
+ if (next < 0) {
+ pos.setErrorIndex(sourceOffset);
+ return NULL; // leave index as is to signal error
+ } else {
+ UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
+ UnicodeString compValue;
+ compValue.append(LEFT_CURLY_BRACE);
+ itos(argNumber, compValue);
+ compValue.append(RIGHT_CURLY_BRACE);
+ if (0 != strValue.compare(compValue)) {
+ argResult.setString(strValue);
+ haveArgResult = TRUE;
+ }
+ sourceOffset = next;
+ }
+ } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
+ tempStatus.setIndex(sourceOffset);
+ double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
+ if (tempStatus.getIndex() == sourceOffset) {
+ pos.setErrorIndex(sourceOffset);
+ return NULL; // leave index as is to signal error
+ }
+ argResult.setDouble(choiceResult);
+ haveArgResult = TRUE;
+ sourceOffset = tempStatus.getIndex();
+ } else if(argType==UMSGPAT_ARG_TYPE_PLURAL || argType==UMSGPAT_ARG_TYPE_SELECT) {
+ // Parsing not supported.
+ ec = U_UNSUPPORTED_ERROR;
+ return NULL;
+ } else {
+ // This should never happen.
+ ec = U_INTERNAL_PROGRAM_ERROR;
+ return NULL;
+ }
+ if (haveArgResult && count <= argNumber) {
+ count = argNumber + 1;
+ }
+ prevIndex=msgPattern.getPart(argLimit).getLimit();
+ i=argLimit;
+ }
+}
+// -------------------------------------
+// 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 {
+ UErrorCode ec = U_ZERO_ERROR;
+ return parse(0, source, pos, count, ec);
+}
+
+// -------------------------------------
+// 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
+{
+ if (msgPattern.hasNamedArguments()) {
+ success = U_ARGUMENT_TYPE_MISMATCH;
+ return NULL;
+ }
+ 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 (fmt == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
+ UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
+ fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
+ }
+ return fmt;
+}
+
+void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (cachedFormatters != NULL) {
+ uhash_removeAll(cachedFormatters);
+ }
+ if (customFormatArgStarts != NULL) {
+ uhash_removeAll(customFormatArgStarts);
+ }
+
+ // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
+ // which we need not examine.
+ int32_t limit = msgPattern.countParts() - 2;
+ argTypeCount = 0;
+ // We also need not look at the first two "parts"
+ // (at most MSG_START and ARG_START) in this loop.
+ // We determine the argTypeCount first so that we can allocateArgTypes
+ // so that the next loop can set argTypes[argNumber].
+ // (This is for the C API which needs the argTypes to read its va_arg list.)
+ for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
+ const MessagePattern::Part& part = msgPattern.getPart(i);
+ if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
+ const int argNumber = part.getValue();
+ if (argNumber >= argTypeCount) {
+ argTypeCount = argNumber + 1;
+ }
+ }
+ }
+ if (!allocateArgTypes(argTypeCount, status)) {
+ return;
+ }
+ // Set all argTypes to kObject, as a "none" value, for lack of any better value.
+ // We never use kObject for real arguments.
+ for (int32_t i = 0; i < argTypeCount; ++i) {
+ argTypes[i] = Formattable::kObject;
+ }
+ hasArgTypeConflicts = FALSE;
+
+ // This loop starts at part index 1 because we do need to examine
+ // ARG_START parts. (But we can ignore the MSG_START.)
+ for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
+ const MessagePattern::Part* part = &msgPattern.getPart(i);
+ if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
+ continue;
+ }
+ UMessagePatternArgType argType = part->getArgType();
+
+ int32_t argNumber = -1;
+ part = &msgPattern.getPart(i + 1);
+ if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
+ argNumber = part->getValue();
+ }
+ Formattable::Type formattableType;
+
+ switch (argType) {
+ case UMSGPAT_ARG_TYPE_NONE:
+ formattableType = Formattable::kString;
+ break;
+ case UMSGPAT_ARG_TYPE_SIMPLE: {
+ int32_t index = i;
+ i += 2;
+ UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
+ UnicodeString style;
+ if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
+ style = msgPattern.getSubstring(*part);
+ ++i;
+ }
+ UParseError parseError;
+ Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
+ setArgStartFormat(index, formatter, status);
+ break;
+ }
+ case UMSGPAT_ARG_TYPE_CHOICE:
+ case UMSGPAT_ARG_TYPE_PLURAL:
+ formattableType = Formattable::kDouble;
+ break;
+ case UMSGPAT_ARG_TYPE_SELECT:
+ formattableType = Formattable::kString;
+ break;
+ default:
+ status = U_INTERNAL_PROGRAM_ERROR; // Should be unreachable.
+ formattableType = Formattable::kString;
+ break;
+ }
+ if (argNumber != -1) {
+ if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
+ hasArgTypeConflicts = TRUE;
+ }
+ argTypes[argNumber] = formattableType;
+ }
+ }
+}
+
+
+Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
+ Formattable::Type& formattableType, UParseError& parseError,
+ UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+ Format* fmt = NULL;
+ int32_t typeID, styleID;
+ DateFormat::EStyle date_style;
+
+ switch (typeID = findKeyword(type, TYPE_IDS)) {
+ case 0: // number
+ formattableType = Formattable::kDouble;
+ switch (findKeyword(style, 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
+ formattableType = Formattable::kLong;
+ fmt = createIntegerFormat(fLocale, ec);
+ break;
+ default: // pattern
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ if (fmt) {
+ DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt);
+ if (decfmt != NULL) {
+ decfmt->applyPattern(style,parseError,ec);
+ }
+ }
+ break;
+ }
+ break;
+
+ case 1: // date
+ case 2: // time
+ formattableType = Formattable::kDate;
+ styleID = findKeyword(style, DATE_STYLE_IDS);
+ date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
+
+ if (typeID == 1) {
+ fmt = DateFormat::createDateInstance(date_style, fLocale);
+ } else {
+ fmt = DateFormat::createTimeInstance(date_style, fLocale);
+ }
+
+ if (styleID < 0 && fmt != NULL) {
+ SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
+ if (sdtfmt != NULL) {
+ sdtfmt->applyPattern(style);
+ }
+ }
+ break;
+
+ case 3: // spellout
+ formattableType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
+ break;
+ case 4: // ordinal
+ formattableType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
+ break;
+ case 5: // duration
+ formattableType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
+ break;
+ default:
+ formattableType = Formattable::kString;
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+
+ return fmt;
+}
+
+
+//-------------------------------------
+// Finds the string, s, in the string array, list.
+int32_t MessageFormat::findKeyword(const UnicodeString& s,
+ const UChar * const *list)
+{
+ if (s.isEmpty()) {
+ return 0; // default
+ }
+
+ int32_t length = s.length();
+ const UChar *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
+ UnicodeString buffer(FALSE, ps, length);
+ // Trims the space characters and turns all characters
+ // in s to lower case.
+ buffer.toLower("");
+ for (int32_t i = 0; list[i]; ++i) {
+ if (!buffer.compare(list[i], u_strlen(list[i]))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Convenience method that ought to be in NumberFormat
+ */
+NumberFormat*
+MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
+ NumberFormat *temp = NumberFormat::createInstance(locale, status);
+ DecimalFormat *temp2;
+ if (temp != NULL && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != NULL) {
+ 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;
+}
+
+UBool
+MessageFormat::usesNamedArguments() const {
+ return msgPattern.hasNamedArguments();
+}
+
+int32_t
+MessageFormat::getArgTypeCount() const {
+ return argTypeCount;
+}
+
+UBool MessageFormat::equalFormats(const void* left, const void* right) {
+ return *(const Format*)left==*(const Format*)right;
+}
+
+
+UBool MessageFormat::DummyFormat::operator==(const Format&) const {
+ return TRUE;
+}
+
+Format* MessageFormat::DummyFormat::clone() const {
+ return new DummyFormat();
+}
+
+UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
+ UnicodeString& appendTo,
+ FieldPosition&,
+ UErrorCode& status) const {
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return appendTo;
+}
+
+void MessageFormat::DummyFormat::parseObject(const UnicodeString&,
+ Formattable&,
+ ParsePosition& ) const {
+}
+
+
+FormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
+ pos=0;
+ fFormatNames = fNameList;
+}
+
+const UnicodeString*
+FormatNameEnumeration::snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < fFormatNames->size()) {
+ return (const UnicodeString*)fFormatNames->elementAt(pos++);
+ }
+ return NULL;
+}
+
+void
+FormatNameEnumeration::reset(UErrorCode& /*status*/) {
+ pos=0;
+}
+
+int32_t
+FormatNameEnumeration::count(UErrorCode& /*status*/) const {
+ return (fFormatNames==NULL) ? 0 : fFormatNames->size();
+}
+
+FormatNameEnumeration::~FormatNameEnumeration() {
+ delete fFormatNames;
+}
+
+
+MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const Locale* loc)
+ : locale(loc), rules(NULL) {
+}
+
+MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
+ // We own the rules but not the locale.
+ delete rules;
+}
+
+UnicodeString MessageFormat::PluralSelectorProvider::select(double number, UErrorCode& ec) const {
+ if (U_FAILURE(ec)) {
+ return UnicodeString(FALSE, OTHER_STRING, 5);
+ }
+ MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
+ if(rules == NULL) {
+ t->rules = PluralRules::forLocale(*locale, ec);
+ if (U_FAILURE(ec)) {
+ return UnicodeString(FALSE, OTHER_STRING, 5);
+ }
+ }
+ return rules->select(number);
+}
+
+void MessageFormat::PluralSelectorProvider::reset(const Locale* loc) {
+ locale = loc;
+ delete rules;
+ rules = NULL;
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/msgfmt_impl.h b/Build/source/libs/icu/icu-4.8.1/i18n/msgfmt_impl.h
new file mode 100644
index 00000000000..699dc37002c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/msgfmt_impl.h
@@ -0,0 +1,43 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, International Business Machines Corporation and
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File MSGFMT.H
+*
+*******************************************************************************
+*/
+
+#ifndef __MSGFMT_IMPL_H__
+#define __MSGFMT_IMPL_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/msgfmt.h"
+#include "uvector.h"
+#include "unicode/strenum.h"
+
+U_NAMESPACE_BEGIN
+
+class FormatNameEnumeration : public StringEnumeration {
+public:
+ FormatNameEnumeration(UVector *fFormatNames, UErrorCode& status);
+ virtual ~FormatNameEnumeration();
+ 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;
+ UVector *fFormatNames;
+};
+
+U_NAMESPACE_END
+
+#endif
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/name2uni.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/name2uni.cpp
new file mode 100644
index 00000000000..b66bcfeda1d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/name2uni.cpp
@@ -0,0 +1,255 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2011, 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 "cmemory.h"
+#include "name2uni.h"
+#include "patternprops.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()
+ NULL
+ };
+ 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 (PatternProps::isWhiteSpace(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-4.8.1/i18n/name2uni.h b/Build/source/libs/icu/icu-4.8.1/i18n/name2uni.h
new file mode 100644
index 00000000000..1324ec3e8d2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/nfrlist.h b/Build/source/libs/icu/icu-4.8.1/i18n/nfrlist.h
new file mode 100644
index 00000000000..282051fb0d1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nfrlist.h
@@ -0,0 +1,97 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2011, 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 != NULL ? fStuff[index] : NULL; }
+ NFRule* remove(uint32_t index) {
+ if (fStuff == NULL) {
+ return NULL;
+ }
+ 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
+ }
+ if (fStuff != NULL) {
+ fStuff[fCount++] = thing;
+ } else {
+ fCapacity = 0;
+ fCount = 0;
+ }
+ }
+ uint32_t size() const { return fCount; }
+ NFRule* last() const { return (fCount > 0 && fStuff != NULL) ? 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-4.8.1/i18n/nfrs.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/nfrs.cpp
new file mode 100644
index 00000000000..b7b93b24b41
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nfrs.cpp
@@ -0,0 +1,945 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2011, 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"
+#include "patternprops.h"
+
+#ifdef RBNF_DEBUG
+#include "cmemory.h"
+#endif
+
+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() && PatternProps::isWhiteSpace(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];
+ if (buf != NULL) {
+ 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-4.8.1/i18n/nfrs.h b/Build/source/libs/icu/icu-4.8.1/i18n/nfrs.h
new file mode 100644
index 00000000000..93a29b08ee7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nfrs.h
@@ -0,0 +1,106 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2009, 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 isParseable() const {
+ UnicodeString prefixpart = UNICODE_STRING_SIMPLE("-prefixpart");
+ UnicodeString postfix = UNICODE_STRING_SIMPLE("-postfix");
+ UnicodeString postfx = UNICODE_STRING_SIMPLE("-postfx");
+
+ return ( name.indexOf(prefixpart) == -1 && name.indexOf(postfix) == -1 && name.indexOf(postfx) == -1 );
+ }
+
+ 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-4.8.1/i18n/nfrule.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/nfrule.cpp
new file mode 100644
index 00000000000..46932273754
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nfrule.cpp
@@ -0,0 +1,1475 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2011, 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 "patternprops.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() && PatternProps::isWhiteSpace(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 (PatternProps::isWhiteSpace(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 (PatternProps::isWhiteSpace(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];
+ if (buf != NULL) {
+ 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) {
+ UErrorCode status = U_ZERO_ERROR;
+ // 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, status);
+ if (U_FAILURE(status)) { // Memory allocation error.
+ return;
+ }
+ 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
+{
+ UErrorCode status = U_ZERO_ERROR;
+ // 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, status)) {
+ if (U_FAILURE(status)) { //Memory allocation error.
+ return 0;
+ }
+ 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, UErrorCode& status) 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);
+ // Check for memory allocation error.
+ if (collator == NULL || strIter == NULL || prefixIter == NULL) {
+ delete collator;
+ delete strIter;
+ delete prefixIter;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ 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;
+ UErrorCode status = U_ZERO_ERROR;
+ while (p < str.length() && keyLen == 0) {
+ temp.setTo(str, p, str.length() - p);
+ keyLen = prefixLength(temp, key, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ 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, UErrorCode& status) 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);
+
+ // Memory allocation error check.
+ if (collator == NULL || iter == NULL) {
+ delete collator;
+ delete iter;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+
+ 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-4.8.1/i18n/nfrule.h b/Build/source/libs/icu/icu-4.8.1/i18n/nfrule.h
new file mode 100644
index 00000000000..8422a20c1d6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nfrule.h
@@ -0,0 +1,114 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2008, 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, UErrorCode& status) const;
+ UBool allIgnorable(const UnicodeString& str, UErrorCode& status) 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-4.8.1/i18n/nfsubs.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/nfsubs.cpp
new file mode 100644
index 00000000000..4348f5d4fc1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nfsubs.cpp
@@ -0,0 +1,1317 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2010, 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 <stdio.h>
+#include <typeinfo> // for 'typeid' to work
+
+#include "nfsubs.h"
+#include "digitlst.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 typeid(*this) == typeid(rhs)
+ && 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);
+ dl.roundFixedPoint(20); // round to 20 fraction digits.
+ dl.reduce(); // Removes any trailing zeros.
+
+ UBool pad = FALSE;
+ for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
+ // Loop iterates over fraction digits, starting with the LSD.
+ // include both real digits from the number, and zeros
+ // to the left of the MSD but to the right of the decimal point.
+ if (pad && useSpaces) {
+ toInsertInto.insert(_pos + getPos(), gSpace);
+ } else {
+ pad = TRUE;
+ }
+ int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
+ getRuleSet()->format(digit, toInsertInto, _pos + getPos());
+ }
+
+ 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.getCount() == 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-4.8.1/i18n/nfsubs.h b/Build/source/libs/icu/icu-4.8.1/i18n/nfsubs.h
new file mode 100644
index 00000000000..644b4b2f6e1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/nortrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/nortrans.cpp
new file mode 100644
index 00000000000..329fb910521
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nortrans.cpp
@@ -0,0 +1,175 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2010, 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/normalizer2.h"
+#include "cstring.h"
+#include "nortrans.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NormalizationTransliterator)
+
+static inline Transliterator::Token cstrToken(const char *s) {
+ return Transliterator::pointerToken((void *)s);
+}
+
+/**
+ * System registration hook.
+ */
+void NormalizationTransliterator::registerIDs() {
+ // In the Token, the byte after the NUL is the UNormalization2Mode.
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFC"),
+ _create, cstrToken("nfc\0\0"));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFKC"),
+ _create, cstrToken("nfkc\0\0"));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFD"),
+ _create, cstrToken("nfc\0\1"));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFKD"),
+ _create, cstrToken("nfkc\0\1"));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-FCD"),
+ _create, cstrToken("nfc\0\2"));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-FCC"),
+ _create, cstrToken("nfc\0\3"));
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("NFC"),
+ UNICODE_STRING_SIMPLE("NFD"), TRUE);
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("NFKC"),
+ UNICODE_STRING_SIMPLE("NFKD"), TRUE);
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("FCC"),
+ UNICODE_STRING_SIMPLE("NFD"), FALSE);
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("FCD"),
+ UNICODE_STRING_SIMPLE("FCD"), FALSE);
+}
+
+/**
+ * Factory methods
+ */
+Transliterator* NormalizationTransliterator::_create(const UnicodeString& ID,
+ Token context) {
+ const char *name = (const char *)context.pointer;
+ UNormalization2Mode mode = (UNormalization2Mode)uprv_strchr(name, 0)[1];
+ UErrorCode errorCode = U_ZERO_ERROR;
+ const Normalizer2 *norm2 = Normalizer2::getInstance(NULL, name, mode, errorCode);
+ if(U_SUCCESS(errorCode)) {
+ return new NormalizationTransliterator(ID, *norm2);
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Constructs a transliterator.
+ */
+NormalizationTransliterator::NormalizationTransliterator(const UnicodeString& id,
+ const Normalizer2 &norm2) :
+ Transliterator(id, 0), fNorm2(norm2) {}
+
+/**
+ * Destructor.
+ */
+NormalizationTransliterator::~NormalizationTransliterator() {
+}
+
+/**
+ * Copy constructor.
+ */
+NormalizationTransliterator::NormalizationTransliterator(const NormalizationTransliterator& o) :
+ Transliterator(o), fNorm2(o.fNorm2) {}
+
+/**
+ * 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;
+ if(start >= limit) {
+ return;
+ }
+
+ /*
+ * 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:
+
+ UnicodeString input, normalized;
+ int32_t length = limit - start;
+ _Replaceable_extractBetween(text, start, limit, input.getBuffer(length));
+ input.releaseBuffer(length);
+
+ UErrorCode status = U_ZERO_ERROR;
+ fNorm2.normalize(input, normalized, status);
+
+ text.handleReplaceBetween(start, limit, normalized);
+
+ int32_t delta = normalized.length() - length;
+ offsets.contextLimit += delta;
+ offsets.limit += delta;
+ offsets.start = limit + delta;
+
+ */
+ UErrorCode errorCode = U_ZERO_ERROR;
+ UnicodeString segment;
+ UnicodeString normalized;
+ UChar32 c = text.char32At(start);
+ do {
+ int32_t prev = start;
+ // Skip at least one character so we make progress.
+ // c holds the character at start.
+ segment.remove();
+ do {
+ segment.append(c);
+ start += U16_LENGTH(c);
+ } while(start < limit && !fNorm2.hasBoundaryBefore(c = text.char32At(start)));
+ if(start == limit && isIncremental && !fNorm2.hasBoundaryAfter(c)) {
+ // stop in incremental mode when we reach the input limit
+ // in case there are additional characters that could change the
+ // normalization result
+ start=prev;
+ break;
+ }
+ fNorm2.normalize(segment, normalized, errorCode);
+ if(U_FAILURE(errorCode)) {
+ break;
+ }
+ if(segment != normalized) {
+ // replace the input chunk with its normalized form
+ text.handleReplaceBetween(prev, start, normalized);
+
+ // update all necessary indexes accordingly
+ int32_t delta = normalized.length() - (start - prev);
+ start += delta;
+ limit += delta;
+ }
+ } while(start < limit);
+
+ offsets.start = start;
+ offsets.contextLimit += limit - offsets.limit;
+ offsets.limit = limit;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/nortrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/nortrans.h
new file mode 100644
index 00000000000..634f534f7d4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/nortrans.h
@@ -0,0 +1,100 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2010, 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/normalizer2.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs normalization.
+ * @author Alan Liu
+ */
+class NormalizationTransliterator : public Transliterator {
+ const Normalizer2 &fNorm2;
+
+ 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, const Normalizer2 &norm2);
+
+private:
+ /**
+ * Assignment operator.
+ */
+ NormalizationTransliterator& operator=(const NormalizationTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/nultrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/nultrans.cpp
new file mode 100644
index 00000000000..820c43d07e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/nultrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/nultrans.h
new file mode 100644
index 00000000000..699c323f8c6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/numfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/numfmt.cpp
new file mode 100644
index 00000000000..14d609d1eb0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/numfmt.cpp
@@ -0,0 +1,1312 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 "unicode/numsys.h"
+#include "unicode/rbnf.h"
+#include "charstr.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 "umutex.h"
+#include "mutex.h"
+#include "digitlst.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" */
+};
+static const UChar gLastResortIsoCurrencyPat[] = {
+ 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "\u00A4\u00A4#0.00;(\u00A4\u00A4#0.00)" */
+};
+static const UChar gLastResortPluralCurrencyPat[] = {
+ 0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/
+};
+
+static const UChar gSingleCurrencySign[] = {0xA4, 0};
+static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0};
+
+static const UChar gSlash = 0x2f;
+
+// 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[UNUM_FORMAT_STYLE_COUNT] = {
+ NULL, // UNUM_PATTERN_DECIMAL
+ gLastResortDecimalPat, // UNUM_DECIMAL
+ gLastResortCurrencyPat, // UNUM_CURRENCY
+ gLastResortPercentPat, // UNUM_PERCENT
+ gLastResortScientificPat, // UNUM_SCIENTIFIC
+ NULL, // UNUM_SPELLOUT
+ NULL, // UNUM_ORDINAL
+ NULL, // UNUM_DURATION
+ NULL, // UNUM_NUMBERING_SYSTEM
+ NULL, // UNUM_PATTERN_RULEBASED
+ gLastResortIsoCurrencyPat, // UNUM_CURRENCY_ISO
+ gLastResortPluralCurrencyPat // UNUM_CURRENCY_PLURAL
+};
+
+// Keys used for accessing resource bundles
+
+static const char *gNumberElements = "NumberElements";
+static const char *gLatn = "latn";
+static const char *gPatterns = "patterns";
+static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = {
+ NULL, // UNUM_PATTERN_DECIMAL
+ "decimalFormat", // UNUM_DECIMAL
+ "currencyFormat", // UNUM_CURRENCY
+ "percentFormat", // UNUM_PERCENT
+ "scientificFormat", // UNUM_SCIENTIFIC
+ NULL, // UNUM_SPELLOUT
+ NULL, // UNUM_ORDINAL
+ NULL, // UNUM_DURATION
+ NULL, // UNUM_NUMBERING_SYSTEM
+ NULL, // UNUM_PATTERN_RULEBASED
+ // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL,
+ // the pattern is the same as the pattern of UNUM_CURRENCY
+ // except for replacing the single currency sign with
+ // double currency sign or triple currency sign.
+ "currencyFormat", // UNUM_CURRENCY_ISO
+ "currencyFormat" // UNUM_CURRENCY_PLURAL
+};
+
+// Static hashtable cache of NumberingSystem objects used by NumberFormat
+static UHashtable * NumberingSystem_cache = NULL;
+
+static UMTX nscacheMutex = NULL;
+
+#if !UCONFIG_NO_SERVICE
+static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
+#endif
+
+/**
+ * Release all static memory held by Number Format.
+ */
+U_CDECL_BEGIN
+static void U_CALLCONV
+deleteNumberingSystem(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER NumberingSystem *)obj;
+}
+
+static UBool U_CALLCONV numfmt_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+ if (gService) {
+ delete gService;
+ gService = NULL;
+ }
+#endif
+ if (NumberingSystem_cache) {
+ // delete NumberingSystem_cache;
+ uhash_close(NumberingSystem_cache);
+ NumberingSystem_cache = NULL;
+ }
+
+ return TRUE;
+}
+U_CDECL_END
+
+// *****************************************************************************
+// 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),
+ fLenient(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)
+ {
+ Format::operator=(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);
+ fLenient = rhs.fLenient;
+ }
+ 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 (!(fLenient == other->fLenient)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fLenient != ");
+ }
+ 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 &&
+ fLenient == other->fLenient)));
+}
+
+// -------------------------------------
+// Default implementation sets unsupported error; subclasses should
+// override.
+
+UnicodeString&
+NumberFormat::format(double /* unused number */,
+ UnicodeString& toAppendTo,
+ FieldPositionIterator* /* unused posIter */,
+ UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return toAppendTo;
+}
+
+// -------------------------------------
+// Default implementation sets unsupported error; subclasses should
+// override.
+
+UnicodeString&
+NumberFormat::format(int32_t /* unused number */,
+ UnicodeString& toAppendTo,
+ FieldPositionIterator* /* unused posIter */,
+ UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return toAppendTo;
+}
+
+// -------------------------------------
+// Default implementation sets unsupported error; subclasses should
+// override.
+
+UnicodeString&
+NumberFormat::format(int64_t /* unused number */,
+ UnicodeString& toAppendTo,
+ FieldPositionIterator* /* unused posIter */,
+ UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return toAppendTo;
+}
+
+// -------------------------------------
+// Decimal Number format() default implementation
+// Subclasses do not normally override this function, but rather the DigitList
+// formatting functions..
+// The expected call chain from here is
+// this function ->
+// NumberFormat::format(Formattable ->
+// DecimalFormat::format(DigitList
+//
+// Or, for subclasses of Formattable that do not know about DigitList,
+// this Function ->
+// NumberFormat::format(Formattable ->
+// NumberFormat::format(DigitList ->
+// XXXFormat::format(double
+
+UnicodeString&
+NumberFormat::format(const StringPiece &decimalNum,
+ UnicodeString& toAppendTo,
+ FieldPositionIterator* fpi,
+ UErrorCode& status) const
+{
+ Formattable f;
+ f.setDecimalNumber(decimalNum, status);
+ format(f, toAppendTo, fpi, status);
+ return toAppendTo;
+}
+
+// -------------------------------------
+// Formats the number object and save the format
+// result in the toAppendTo string buffer.
+
+// utility to save/restore state, used in two overloads
+// of format(const Formattable&...) below.
+
+class ArgExtractor {
+ NumberFormat *ncnf;
+ const Formattable* num;
+ UBool setCurr;
+ UChar save[4];
+
+ public:
+ ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status);
+ ~ArgExtractor();
+
+ const Formattable* number(void) const;
+};
+
+inline const Formattable*
+ArgExtractor::number(void) const {
+ return num;
+}
+
+ArgExtractor::ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status)
+ : ncnf((NumberFormat*) &nf), num(&obj), setCurr(FALSE) {
+
+ const UObject* o = obj.getObject(); // most commonly o==NULL
+ const CurrencyAmount* amt;
+ if (o != NULL && (amt = dynamic_cast<const CurrencyAmount*>(o)) != NULL) {
+ // getISOCurrency() returns a pointer to internal storage, so we
+ // copy it to retain it across the call to setCurrency().
+ const UChar* curr = amt->getISOCurrency();
+ u_strcpy(save, nf.getCurrency());
+ setCurr = (u_strcmp(curr, save) != 0);
+ if (setCurr) {
+ ncnf->setCurrency(curr, status);
+ }
+ num = &amt->getNumber();
+ }
+}
+
+ArgExtractor::~ArgExtractor() {
+ if (setCurr) {
+ UErrorCode ok = U_ZERO_ERROR;
+ ncnf->setCurrency(save, ok); // always restore currency
+ }
+}
+
+UnicodeString& NumberFormat::format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ // DecimalFormat overrides this function, and handles DigitList based big decimals.
+ // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
+ // so this default implementation falls back to formatting decimal numbers as doubles.
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ double dnum = number.getDouble();
+ format(dnum, appendTo, posIter, status);
+ return appendTo;
+}
+
+
+
+UnicodeString&
+NumberFormat::format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode &status) const {
+ // DecimalFormat overrides this function, and handles DigitList based big decimals.
+ // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
+ // so this default implementation falls back to formatting decimal numbers as doubles.
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ double dnum = number.getDouble();
+ format(dnum, appendTo, pos, status);
+ return appendTo;
+}
+
+UnicodeString&
+NumberFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return appendTo;
+
+ ArgExtractor arg(*this, obj, status);
+ const Formattable *n = arg.number();
+
+ if (n->isNumeric() && n->getDigitList() != NULL) {
+ // Decimal Number. We will have a DigitList available if the value was
+ // set to a decimal number, or if the value originated with a parse.
+ //
+ // The default implementation for formatting a DigitList converts it
+ // to a double, and formats that, allowing formatting classes that don't
+ // know about DigitList to continue to operate as they had.
+ //
+ // DecimalFormat overrides the DigitList formatting functions.
+ format(*n->getDigitList(), appendTo, pos, status);
+ } else {
+ 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;
+ }
+ }
+
+ return appendTo;
+}
+
+// -------------------------------------x
+// Formats the number object and save the format
+// result in the toAppendTo string buffer.
+
+UnicodeString&
+NumberFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return appendTo;
+
+ ArgExtractor arg(*this, obj, status);
+ const Formattable *n = arg.number();
+
+ if (n->isNumeric() && n->getDigitList() != NULL) {
+ // Decimal Number
+ format(*n->getDigitList(), appendTo, posIter, status);
+ } else {
+ switch (n->getType()) {
+ case Formattable::kDouble:
+ format(n->getDouble(), appendTo, posIter, status);
+ break;
+ case Formattable::kLong:
+ format(n->getLong(), appendTo, posIter, status);
+ break;
+ case Formattable::kInt64:
+ format(n->getInt64(), appendTo, posIter, status);
+ break;
+ default:
+ status = U_INVALID_FORMAT_ERROR;
+ break;
+ }
+ }
+
+ 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);
+ CurrencyAmount *tempCurAmnt = new CurrencyAmount(n, curr, ec); // Use for null testing.
+ if (U_FAILURE(ec) || tempCurAmnt == NULL) {
+ pos.setIndex(start); // indicate failure
+ } else {
+ result.adoptObject(tempCurAmnt);
+ }
+ }
+ }
+ return result;
+}
+
+// -------------------------------------
+// Sets to only parse integers.
+
+void
+NumberFormat::setParseIntegerOnly(UBool value)
+{
+ fParseIntegerOnly = value;
+}
+
+// -------------------------------------
+// Sets whether lenient parse is enabled.
+
+void
+NumberFormat::setLenient(UBool enable)
+{
+ fLenient = enable;
+}
+
+// -------------------------------------
+// Create a number style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), UNUM_DECIMAL, status);
+}
+
+// -------------------------------------
+// Create a number style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, UNUM_DECIMAL, 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, UNUM_CURRENCY, status);
+}
+
+// -------------------------------------
+// Create a percent style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createPercentInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), UNUM_PERCENT, status);
+}
+
+// -------------------------------------
+// Create a percent style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, UNUM_PERCENT, status);
+}
+
+// -------------------------------------
+// Create a scientific style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createScientificInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), UNUM_SCIENTIFIC, status);
+}
+
+// -------------------------------------
+// Create a scientific style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, UNUM_SCIENTIFIC, status);
+}
+
+// -------------------------------------
+
+const Locale* U_EXPORT2
+NumberFormat::getAvailableLocales(int32_t& count)
+{
+ return Locale::getAvailableLocales(count);
+}
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+
+#if !UCONFIG_NO_SERVICE
+
+// -------------------------------------
+
+class ICUNumberFormatFactory : public ICUResourceBundleFactory {
+protected:
+ virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
+ return NumberFormat::makeInstance(loc, (UNumberFormatStyle)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);
+ 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, (UNumberFormatStyle)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) {
+ NFFactory *tempnnf = new NFFactory(toAdopt);
+ if (tempnnf != NULL) {
+ return service->registerFactory(tempnnf, 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, UNumberFormatStyle 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.
+
+UBool
+NumberFormat::isStyleSupported(UNumberFormatStyle style) {
+ return gLastResortNumberPatterns[style] != NULL;
+}
+
+NumberFormat*
+NumberFormat::makeInstance(const Locale& desiredLocale,
+ UNumberFormatStyle style,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status)) return NULL;
+
+ if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ // Some styles are not supported. This is a result of merging
+ // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle.
+ // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations:
+ // this one and unum_open().
+ // The UNUM_PATTERN_ styles are not supported here
+ // because this method does not take a pattern string.
+ if (!isStyleSupported(style)) {
+ status = U_UNSUPPORTED_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 (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) {
+ Win32NumberFormat *f = NULL;
+ UBool curr = TRUE;
+
+ switch (style) {
+ case UNUM_DECIMAL:
+ curr = FALSE;
+ // fall-through
+
+ case UNUM_CURRENCY:
+ case UNUM_CURRENCY_ISO: // do not support plural formatting here
+ case UNUM_CURRENCY_PLURAL:
+ f = new Win32NumberFormat(desiredLocale, curr, status);
+
+ if (U_SUCCESS(status)) {
+ return f;
+ }
+
+ delete f;
+ break;
+
+ default:
+ break;
+ }
+ }
+#endif
+
+ LocalPointer<DecimalFormatSymbols> symbolsToAdopt;
+ UnicodeString pattern;
+ LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &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.adoptInstead(new DecimalFormatSymbols(status));
+ if (symbolsToAdopt.isNull()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ // Creates a DecimalFormat instance with the last resort number patterns.
+ pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
+ }
+ else {
+ // Loads the decimal symbols of the desired locale.
+ symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status));
+ if (symbolsToAdopt.isNull()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ UResourceBundle *resource = ownedResource.orphan();
+ resource = ures_getByKeyWithFallback(resource, gNumberElements, resource, &status);
+ // TODO : Get patterns on a per numbering system basis, for right now assumes "latn" for patterns
+ resource = ures_getByKeyWithFallback(resource, gLatn, resource, &status);
+ resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
+ ownedResource.adoptInstead(resource);
+
+ int32_t patLen = 0;
+ const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
+
+ // Creates the specified decimal format style of the desired locale.
+ pattern.setTo(TRUE, patResStr, patLen);
+ }
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){
+ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
+ if(currPattern!=NULL){
+ pattern.setTo(currPattern, u_strlen(currPattern));
+ }
+ }
+
+ // Use numbering system cache hashtable
+ UHashtable *cache;
+ UMTX_CHECK(&nscacheMutex, NumberingSystem_cache, cache);
+
+ // Check cache we got, create if non-existant
+ if (cache == NULL) {
+ cache = uhash_open(uhash_hashLong,
+ uhash_compareLong,
+ NULL,
+ &status);
+
+ if (U_FAILURE(status)) {
+ // cache not created - out of memory
+ status = U_ZERO_ERROR; // work without the cache
+ cache = NULL;
+ } else {
+ // cache created
+ uhash_setValueDeleter(cache, deleteNumberingSystem);
+
+ // set final NumberingSystem_cache value
+ Mutex lock(&nscacheMutex);
+ if (NumberingSystem_cache == NULL) {
+ NumberingSystem_cache = cache;
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
+ } else {
+ uhash_close(cache);
+ cache = NumberingSystem_cache;
+ }
+ }
+ }
+
+ // Get cached numbering system
+ LocalPointer<NumberingSystem> ownedNs;
+ NumberingSystem *ns = NULL;
+ if (cache != NULL) {
+ // TODO: Bad hash key usage, see ticket #8504.
+ int32_t hashKey = desiredLocale.hashCode();
+
+ Mutex lock(&nscacheMutex);
+ ns = (NumberingSystem *)uhash_iget(cache, hashKey);
+ if (ns == NULL) {
+ ns = NumberingSystem::createInstance(desiredLocale,status);
+ uhash_iput(cache, hashKey, (void*)ns, &status);
+ }
+ } else {
+ ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status));
+ ns = ownedNs.getAlias();
+ }
+
+ // check results of getting a numbering system
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ NumberFormat *f;
+ if (ns->isAlgorithmic()) {
+ UnicodeString nsDesc;
+ UnicodeString nsRuleSetGroup;
+ UnicodeString nsRuleSetName;
+ Locale nsLoc;
+ URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM;
+
+ nsDesc.setTo(ns->getDescription());
+ int32_t firstSlash = nsDesc.indexOf(gSlash);
+ int32_t lastSlash = nsDesc.lastIndexOf(gSlash);
+ if ( lastSlash > firstSlash ) {
+ CharString nsLocID;
+
+ nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status);
+ nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1);
+ nsRuleSetName.setTo(nsDesc,lastSlash+1);
+
+ nsLoc = Locale::createFromName(nsLocID.data());
+
+ UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules");
+ if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) {
+ desiredRulesType = URBNF_SPELLOUT;
+ }
+ } else {
+ nsLoc = desiredLocale;
+ nsRuleSetName.setTo(nsDesc);
+ }
+
+ RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status);
+ if (r == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ r->setDefaultRuleSet(nsRuleSetName,status);
+ f = r;
+ } else {
+ // replace single currency sign in the pattern with double currency sign
+ // if the style is UNUM_CURRENCY_ISO
+ if (style == UNUM_CURRENCY_ISO) {
+ pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign);
+ }
+
+ // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails.
+ DecimalFormatSymbols *syms = symbolsToAdopt.orphan();
+ f = new DecimalFormat(pattern, syms, style, status);
+ if (f == NULL) {
+ delete syms;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ }
+
+ f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status));
+ if (U_FAILURE(status)) {
+ delete f;
+ return NULL;
+ }
+ return f;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/numsys.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/numsys.cpp
new file mode 100644
index 00000000000..534ed156cef
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/numsys.cpp
@@ -0,0 +1,247 @@
+/*
+*******************************************************************************
+* Copyright (C) 2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+*
+* File NUMSYS.CPP
+*
+* Modification History:*
+* Date Name Description
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "unicode/uloc.h"
+#include "unicode/schriter.h"
+#include "unicode/numsys.h"
+#include "cstring.h"
+#include "uresimp.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+// Useful constants
+
+#define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789");
+static const char gNumberingSystems[] = "numberingSystems";
+static const char gNumberElements[] = "NumberElements";
+static const char gDefault[] = "default";
+static const char gDesc[] = "desc";
+static const char gRadix[] = "radix";
+static const char gAlgorithmic[] = "algorithmic";
+static const char gLatn[] = "latn";
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem)
+
+ /**
+ * Default Constructor.
+ *
+ * @draft ICU 4.2
+ */
+
+NumberingSystem::NumberingSystem() {
+ radix = 10;
+ algorithmic = FALSE;
+ UnicodeString defaultDigits = DEFAULT_DIGITS;
+ desc.setTo(defaultDigits);
+ uprv_strcpy(name,gLatn);
+}
+
+ /**
+ * Copy constructor.
+ * @draft ICU 4.2
+ */
+
+NumberingSystem::NumberingSystem(const NumberingSystem& other)
+: UObject(other) {
+ *this=other;
+}
+
+NumberingSystem* U_EXPORT2
+NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ if ( radix_in < 2 ) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ if ( !isAlgorithmic_in ) {
+ if ( desc_in.countChar32() != radix_in || !isValidDigitString(desc_in)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ }
+
+ NumberingSystem *ns = new NumberingSystem();
+
+ ns->setRadix(radix_in);
+ ns->setDesc(desc_in);
+ ns->setAlgorithmic(isAlgorithmic_in);
+ ns->setName(NULL);
+ return ns;
+
+}
+
+
+NumberingSystem* U_EXPORT2
+NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ char buffer[ULOC_KEYWORDS_CAPACITY];
+ int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status);
+ if ( count > 0 ) { // @numbers keyword was specified in the locale
+ buffer[count] = '\0'; // Make sure it is null terminated.
+ return NumberingSystem::createInstanceByName(buffer,status);
+ } else { // Find the default numbering system for this locale.
+ UResourceBundle *resource = ures_open(NULL, inLocale.getName(), &status);
+ UResourceBundle *numberElementsRes = ures_getByKey(resource,gNumberElements,NULL,&status);
+ const UChar *defaultNSName =
+ ures_getStringByKeyWithFallback(numberElementsRes, gDefault, &count, &status);
+ ures_close(numberElementsRes);
+ ures_close(resource);
+
+ if (U_FAILURE(status)) {
+ status = U_USING_FALLBACK_WARNING;
+ NumberingSystem *ns = new NumberingSystem();
+ return ns;
+ }
+
+ if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // Default numbering system found
+ u_UCharsToChars(defaultNSName,buffer,count);
+ buffer[count] = '\0'; // Make sure it is null terminated.
+ return NumberingSystem::createInstanceByName(buffer,status);
+ } else {
+ status = U_USING_FALLBACK_WARNING;
+ NumberingSystem *ns = new NumberingSystem();
+ return ns;
+ }
+
+ }
+}
+
+NumberingSystem* U_EXPORT2
+NumberingSystem::createInstance(UErrorCode& status) {
+ return NumberingSystem::createInstance(Locale::getDefault(), status);
+}
+
+NumberingSystem* U_EXPORT2
+NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) {
+
+ UResourceBundle *numberingSystemsInfo = NULL;
+ UResourceBundle *nsTop, *nsCurrent;
+ const UChar* description = NULL;
+ int32_t radix = 10;
+ int32_t algorithmic = 0;
+ int32_t len;
+
+ numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status);
+ nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status);
+ nsTop = ures_getByKey(nsCurrent,name,NULL,&status);
+ description = ures_getStringByKey(nsTop,gDesc,&len,&status);
+
+ ures_getByKey(nsTop,gRadix,nsCurrent,&status);
+ radix = ures_getInt(nsCurrent,&status);
+
+ ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status);
+ algorithmic = ures_getInt(nsCurrent,&status);
+
+ UBool isAlgorithmic = ( algorithmic == 1 );
+ UnicodeString nsd;
+ nsd.setTo(description);
+
+ ures_close(nsCurrent);
+ ures_close(nsTop);
+ ures_close(numberingSystemsInfo);
+
+ if (U_FAILURE(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+
+ NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status);
+ ns->setName(name);
+ return ns;
+}
+
+ /**
+ * Destructor.
+ * @draft ICU 4.2
+ */
+NumberingSystem::~NumberingSystem() {
+}
+
+int32_t NumberingSystem::getRadix() {
+ return radix;
+}
+
+UnicodeString NumberingSystem::getDescription() {
+ return desc;
+}
+
+const char * NumberingSystem::getName() {
+ return name;
+}
+
+void NumberingSystem::setRadix(int32_t r) {
+ radix = r;
+}
+
+void NumberingSystem::setAlgorithmic(UBool c) {
+ algorithmic = c;
+}
+
+void NumberingSystem::setDesc(UnicodeString d) {
+ desc.setTo(d);
+}
+void NumberingSystem::setName(const char *n) {
+ if ( n == NULL ) {
+ name[0] = (char) 0;
+ } else {
+ uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY);
+ name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated.
+ }
+}
+UBool NumberingSystem::isAlgorithmic() const {
+ return ( algorithmic );
+}
+
+
+UBool NumberingSystem::isValidDigitString(const UnicodeString& str) {
+
+ StringCharacterIterator it(str);
+ UChar32 c;
+ UChar32 prev = 0;
+ int32_t i = 0;
+
+ for ( it.setToStart(); it.hasNext(); ) {
+ c = it.next32PostInc();
+ if ( c > 0xFFFF ) { // Digits outside the BMP are not currently supported
+ return FALSE;
+ }
+ i++;
+ prev = c;
+ }
+ return TRUE;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/olsontz.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/olsontz.cpp
new file mode 100644
index 00000000000..3fe2861d55f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/olsontz.cpp
@@ -0,0 +1,1065 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: July 21 2003
+* Since: ICU 2.8
+**********************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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
+#include "uresimp.h" // struct UResourceBundle
+#include "zonemeta.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);
+}
+// 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
+
+static UBool arrayEqual(const void *a1, const void *a2, int32_t size) {
+ if (a1 == NULL && a2 == NULL) {
+ return TRUE;
+ }
+ if ((a1 != NULL && a2 == NULL) || (a1 == NULL && a2 != NULL)) {
+ return FALSE;
+ }
+ if (a1 == a2) {
+ return TRUE;
+ }
+
+ return (uprv_memcmp(a1, a2, size) == 0);
+}
+
+U_NAMESPACE_BEGIN
+
+#define kTRANS "trans"
+#define kTRANSPRE32 "transPre32"
+#define kTRANSPOST32 "transPost32"
+#define kTYPEOFFSETS "typeOffsets"
+#define kTYPEMAP "typeMap"
+#define kLINKS "links"
+#define kFINALRULE "finalRule"
+#define kFINALRAW "finalRaw"
+#define kFINALYEAR "finalYear"
+
+#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() {
+ canonicalID = NULL;
+
+ transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
+ transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
+
+ typeMapData = NULL;
+
+ typeCount = 1;
+ typeOffsets = ZEROS;
+
+ finalZone = NULL;
+}
+
+/**
+ * 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,
+ const UnicodeString& tzid,
+ UErrorCode& ec) :
+ BasicTimeZone(tzid), finalZone(NULL), 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
+
+ int32_t len;
+ UResourceBundle r;
+ ures_initStackObject(&r);
+
+ // Pre-32bit second transitions
+ ures_getByKey(res, kTRANSPRE32, &r, &ec);
+ transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
+ transitionCountPre32 = len >> 1;
+ if (ec == U_MISSING_RESOURCE_ERROR) {
+ // No pre-32bit transitions
+ transitionTimesPre32 = NULL;
+ transitionCountPre32 = 0;
+ ec = U_ZERO_ERROR;
+ } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+
+ // 32bit second transitions
+ ures_getByKey(res, kTRANS, &r, &ec);
+ transitionTimes32 = ures_getIntVector(&r, &len, &ec);
+ transitionCount32 = len;
+ if (ec == U_MISSING_RESOURCE_ERROR) {
+ // No 32bit transitions
+ transitionTimes32 = NULL;
+ transitionCount32 = 0;
+ ec = U_ZERO_ERROR;
+ } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+
+ // Post-32bit second transitions
+ ures_getByKey(res, kTRANSPOST32, &r, &ec);
+ transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
+ transitionCountPost32 = len >> 1;
+ if (ec == U_MISSING_RESOURCE_ERROR) {
+ // No pre-32bit transitions
+ transitionTimesPost32 = NULL;
+ transitionCountPost32 = 0;
+ ec = U_ZERO_ERROR;
+ } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+
+ // Type offsets list must be of even size, with size >= 2
+ ures_getByKey(res, kTYPEOFFSETS, &r, &ec);
+ typeOffsets = ures_getIntVector(&r, &len, &ec);
+ if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ typeCount = (int16_t) len >> 1;
+
+ // Type map data must be of the same size as the transition count
+ typeMapData = NULL;
+ if (transitionCount() > 0) {
+ ures_getByKey(res, kTYPEMAP, &r, &ec);
+ typeMapData = ures_getBinary(&r, &len, &ec);
+ if (ec == U_MISSING_RESOURCE_ERROR) {
+ // no type mapping data
+ ec = U_INVALID_FORMAT_ERROR;
+ } else if (U_SUCCESS(ec) && len != transitionCount()) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ }
+
+ // Process final rule and data, if any
+ const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
+ ures_getByKey(res, kFINALRAW, &r, &ec);
+ int32_t ruleRaw = ures_getInt(&r, &ec);
+ ures_getByKey(res, kFINALYEAR, &r, &ec);
+ int32_t ruleYear = ures_getInt(&r, &ec);
+ if (U_SUCCESS(ec)) {
+ UnicodeString ruleID(TRUE, ruleIdUStr, len);
+ UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec);
+ const int32_t *ruleData = ures_getIntVector(rule, &len, &ec);
+ if (U_SUCCESS(ec) && len == 11) {
+ UnicodeString emptyStr;
+ finalZone = new SimpleTimeZone(
+ ruleRaw * U_MILLIS_PER_SECOND,
+ emptyStr,
+ (int8_t)ruleData[0], (int8_t)ruleData[1], (int8_t)ruleData[2],
+ ruleData[3] * U_MILLIS_PER_SECOND,
+ (SimpleTimeZone::TimeMode) ruleData[4],
+ (int8_t)ruleData[5], (int8_t)ruleData[6], (int8_t)ruleData[7],
+ ruleData[8] * U_MILLIS_PER_SECOND,
+ (SimpleTimeZone::TimeMode) ruleData[9],
+ ruleData[10] * U_MILLIS_PER_SECOND, ec);
+ if (finalZone == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ finalStartYear = ruleYear;
+
+ // Note: Setting finalStartYear to the finalZone is problematic. When a date is around
+ // year boundary, SimpleTimeZone may return false result when DST is observed at the
+ // beginning of year. We could apply safe margin (day or two), but when one of recurrent
+ // rules falls around year boundary, it could return false result. Without setting the
+ // start year, finalZone works fine around the year boundary of the start year.
+
+ // finalZone->setStartYear(finalStartYear);
+
+
+ // Compute the millis for Jan 1, 0:00 GMT of the finalYear
+
+ // Note: finalStartMillis is used for detecting either if
+ // historic transition data or finalZone to be used. In an
+ // extreme edge case - for example, two transitions fall into
+ // small windows of time around the year boundary, this may
+ // result incorrect offset computation. But I think it will
+ // never happen practically. Yoshito - Feb 20, 2010
+ finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY;
+ }
+ } else {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ ures_close(rule);
+ } else if (ec == U_MISSING_RESOURCE_ERROR) {
+ // No final zone
+ ec = U_ZERO_ERROR;
+ }
+ ures_close(&r);
+
+ // initialize canonical ID
+ canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
+ }
+
+ 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) {
+ canonicalID = other.canonicalID;
+
+ transitionTimesPre32 = other.transitionTimesPre32;
+ transitionTimes32 = other.transitionTimes32;
+ transitionTimesPost32 = other.transitionTimesPost32;
+
+ transitionCountPre32 = other.transitionCountPre32;
+ transitionCount32 = other.transitionCount32;
+ transitionCountPost32 = other.transitionCountPost32;
+
+ typeCount = other.typeCount;
+ typeOffsets = other.typeOffsets;
+ typeMapData = other.typeMapData;
+
+ delete finalZone;
+ finalZone = (other.finalZone != 0) ?
+ (SimpleTimeZone*) other.finalZone->clone() : 0;
+
+ finalStartYear = other.finalStartYear;
+ finalStartMillis = other.finalStartMillis;
+
+ 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) ||
+ (typeid(*this) == typeid(other) &&
+ 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 (finalZone != NULL && year >= finalStartYear) {
+ 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;
+ }
+ if (finalZone != NULL && date >= finalStartMillis) {
+ 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 (finalZone != NULL && date >= finalStartMillis) {
+ 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 = ClockMath::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
+
+int64_t
+OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const {
+ U_ASSERT(transIdx >= 0 && transIdx < transitionCount());
+
+ if (transIdx < transitionCountPre32) {
+ return (((int64_t)((uint32_t)transitionTimesPre32[transIdx << 1])) << 32)
+ | ((int64_t)((uint32_t)transitionTimesPre32[(transIdx << 1) + 1]));
+ }
+
+ transIdx -= transitionCountPre32;
+ if (transIdx < transitionCount32) {
+ return (int64_t)transitionTimes32[transIdx];
+ }
+
+ transIdx -= transitionCount32;
+ return (((int64_t)((uint32_t)transitionTimesPost32[transIdx << 1])) << 32)
+ | ((int64_t)((uint32_t)transitionTimesPost32[(transIdx << 1) + 1]));
+}
+
+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
+ int16_t transCount = transitionCount();
+
+ if (transCount > 0) {
+ double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
+ if (!local && sec < transitionTimeInSeconds(0)) {
+ // Before the first transition time
+ rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
+ dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
+ } else {
+ // Linear search from the end is the fastest approach, since
+ // most lookups will happen at/near the end.
+ int16_t transIdx;
+ for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
+ int64_t transition = transitionTimeInSeconds(transIdx);
+
+ if (local) {
+ int32_t offsetBefore = zoneOffsetAt(transIdx - 1);
+ UBool dstBefore = dstOffsetAt(transIdx - 1) != 0;
+
+ int32_t offsetAfter = zoneOffsetAt(transIdx);
+ UBool dstAfter = dstOffsetAt(transIdx) != 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) {
+ break;
+ }
+ }
+ // transIdx could be -1 when local=true
+ rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
+ dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
+ }
+ } else {
+ // No transitions, single pair of offsets only
+ rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
+ dstoff = initialDstOffset() * 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.
+
+ UDate current = uprv_getUTCtime();
+ if (finalZone != NULL && current >= finalStartMillis) {
+ return finalZone->useDaylightTime();
+ }
+
+ int32_t year, month, dom, dow, doy, mid;
+ Grego::timeToFields(current, year, month, dom, dow, doy, mid);
+
+ // Find start of this year, and start of next year
+ double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
+ double limit = 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) {
+ double transition = transitionTime(i);
+ if (transition >= limit) {
+ break;
+ }
+ if ((transition >= start && dstOffsetAt(i) != 0)
+ || (transition > start && dstOffsetAt(i - 1) != 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;
+ }
+ const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other);
+ if (z == NULL) {
+ return FALSE;
+ }
+
+ // [sic] pointer comparison: typeMapData points into
+ // memory-mapped or DLL space, so if two zones have the same
+ // pointer, they are equal.
+ if (typeMapData == z->typeMapData) {
+ return TRUE;
+ }
+
+ // If the pointers are not equal, the zones may still
+ // be equal if their rules and transitions are equal
+ if ((finalZone == NULL && z->finalZone != NULL)
+ || (finalZone != NULL && z->finalZone == NULL)
+ || (finalZone != NULL && z->finalZone != NULL && *finalZone != *z->finalZone)) {
+ return FALSE;
+ }
+
+ if (finalZone != NULL) {
+ if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) {
+ return FALSE;
+ }
+ }
+ if (typeCount != z->typeCount
+ || transitionCountPre32 != z->transitionCountPre32
+ || transitionCount32 != z->transitionCount32
+ || transitionCountPost32 != z->transitionCountPost32) {
+ return FALSE;
+ }
+
+ return
+ arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1)
+ && arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32)
+ && arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1)
+ && arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1)
+ && arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount());
+}
+
+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;
+
+ // Create initial rule
+ raw = initialRawOffset() * U_MILLIS_PER_SECOND;
+ dst = initialDstOffset() * U_MILLIS_PER_SECOND;
+ initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
+ // Check to make sure initialRule was created
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+
+ int32_t transCount = transitionCount();
+ if (transCount > 0) {
+ int16_t transitionIdx, typeIdx;
+
+ // We probably no longer need to check the first "real" transition
+ // here, because the new tzcode remove such transitions already.
+ // For now, keeping this code for just in case. Feb 19, 2010 Yoshito
+ firstTZTransitionIdx = 0;
+ for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) {
+ if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type
+ break;
+ }
+ firstTZTransitionIdx++;
+ }
+ if (transitionIdx == transCount) {
+ // Actually no transitions...
+ } else {
+ // Build historic rule array
+ UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transCount); /* 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 < transCount; transitionIdx++) {
+ if (typeIdx == (int16_t)typeMapData[transitionIdx]) {
+ UDate tt = (UDate)transitionTime(transitionIdx);
+ if (finalZone == NULL || tt <= finalStartMillis) {
+ // Exclude transitions after finalMillis
+ times[nTimes++] = tt;
+ }
+ }
+ }
+ if (nTimes > 0) {
+ // Create a TimeArrayTimeZoneRule
+ raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND;
+ dst = typeOffsets[(typeIdx << 1) + 1] * 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);
+ // Check for memory allocation error
+ if (historicRules[typeIdx] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ }
+ }
+ uprv_free(times);
+
+ // Create initial transition
+ typeIdx = (int16_t)typeMapData[firstTZTransitionIdx];
+ firstTZTransition = new TimeZoneTransition((UDate)transitionTime(firstTZTransitionIdx),
+ *initialRule, *historicRules[typeIdx]);
+ // Check to make sure firstTZTransition was created.
+ if (firstTZTransition == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ }
+ }
+ if (finalZone != NULL) {
+ // Get the first occurence of final rule starts
+ UDate startTime = (UDate)finalStartMillis;
+ 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.
+ * 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();
+ // Check to make sure finalZone was actually cloned.
+ if (finalZoneWithStartYear == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ finalZoneWithStartYear->setStartYear(finalStartYear);
+
+ TimeZoneTransition tzt;
+ finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
+ firstFinalRule = tzt.getTo()->clone();
+ // Check to make sure firstFinalRule received proper clone.
+ if (firstFinalRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ startTime = tzt.getTime();
+ } else {
+ // final rule with no transitions
+ finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
+ // Check to make sure finalZone was actually cloned.
+ if (finalZoneWithStartYear == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ finalZone->getID(tzid);
+ firstFinalRule = new TimeArrayTimeZoneRule(tzid,
+ finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME);
+ // Check firstFinalRule was properly created.
+ if (firstFinalRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ }
+ TimeZoneRule *prevRule = NULL;
+ if (transCount > 0) {
+ prevRule = historicRules[typeMapData[transCount - 1]];
+ }
+ if (prevRule == NULL) {
+ // No historic transitions, but only finalZone available
+ prevRule = initialRule;
+ }
+ firstFinalTZTransition = new TimeZoneTransition();
+ // Check to make sure firstFinalTZTransition was created before dereferencing
+ if (firstFinalTZTransition == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ 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 transCount = transitionCount();
+ int16_t ttidx = transCount - 1;
+ for (; ttidx >= firstTZTransitionIdx; ttidx--) {
+ UDate t = (UDate)transitionTime(ttidx);
+ if (base > t || (!inclusive && base == t)) {
+ break;
+ }
+ }
+ if (ttidx == transCount - 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[typeMapData[ttidx + 1]];
+ TimeZoneRule *from = historicRules[typeMapData[ttidx]];
+ UDate startTime = (UDate)transitionTime(ttidx+1);
+
+ // 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)transitionTime(ttidx);
+ 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[typeMapData[ttidx]];
+ TimeZoneRule *from = historicRules[typeMapData[ttidx-1]];
+ UDate startTime = (UDate)transitionTime(ttidx);
+
+ // 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-4.8.1/i18n/olsontz.h b/Build/source/libs/icu/icu-4.8.1/i18n/olsontz.h
new file mode 100644
index 00000000000..05e89b25085
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/olsontz.h
@@ -0,0 +1,446 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2011, 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 tz 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 two different formats.
+ *
+ * a. Zone (table). A zone is a table resource contains several
+ * type of resources below:
+ *
+ * - typeOffsets:intvector (Required)
+ *
+ * Sets of UTC raw/dst offset pairs in seconds. Entries at
+ * 2n represents raw offset and 2n+1 represents dst offset
+ * paired with the raw offset at 2n. The very first pair represents
+ * the initial zone offset (before the first transition) always.
+ *
+ * - trans:intvector (Optional)
+ *
+ * List of transition times represented by 32bit seconds from the
+ * epoch (1970-01-01T00:00Z) in ascending order.
+ *
+ * - transPre32/transPost32:intvector (Optional)
+ *
+ * List of transition times before/after 32bit minimum seconds.
+ * Each time is represented by a pair of 32bit integer.
+ *
+ * - typeMap:bin (Optional)
+ *
+ * Array of bytes representing the mapping between each transition
+ * time (transPre32/trans/transPost32) and its corresponding offset
+ * data (typeOffsets).
+ *
+ * - finalRule:string (Optional)
+ *
+ * If a recurrent transition rule is applicable to a zone forever
+ * after the final transition time, finalRule represents the rule
+ * in Rules data.
+ *
+ * - finalRaw:int (Optional)
+ *
+ * When finalRule is available, finalRaw is required and specifies
+ * the raw (base) offset of the rule.
+ *
+ * - finalYear:int (Optional)
+ *
+ * When finalRule is available, finalYear is required and specifies
+ * the start year of the rule.
+ *
+ * - links:intvector (Optional)
+ *
+ * When this zone data is shared with other zones, links specifies
+ * all zones including the zone itself. Each zone is referenced by
+ * integer index.
+ *
+ * b. Link (int, length 1). A link 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. This data
+ * is corresponding to Link data in the tz database.
+ *
+ *
+ * 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. Regions. An array specifies mapping between zones and regions.
+ * Each item is either a 2-letter ISO country code or "001"
+ * (UN M.49 - World). This data is generated from "zone.tab"
+ * in the tz database.
+ */
+class U_I18N_API 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 tzid the time zone ID
+ * @param ec input-output error code
+ */
+ OlsonTimeZone(const UResourceBundle* top,
+ const UResourceBundle* res,
+ const UnicodeString& tzid,
+ 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.
+ */
+ 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.
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
+
+ /**
+ * Internal API returning the canonical ID of this zone.
+ * This ID won't be affected by setID().
+ */
+ const UChar *getCanonicalID() 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;
+
+ int16_t transitionCount() const;
+
+ int64_t transitionTimeInSeconds(int16_t transIdx) const;
+ double transitionTime(int16_t transIdx) const;
+
+ /*
+ * Following 3 methods return an offset at the given transition time index.
+ * When the index is negative, return the initial offset.
+ */
+ int32_t zoneOffsetAt(int16_t transIdx) const;
+ int32_t rawOffsetAt(int16_t transIdx) const;
+ int32_t dstOffsetAt(int16_t transIdx) const;
+
+ /*
+ * Following methods return the initial offset.
+ */
+ int32_t initialRawOffset() const;
+ int32_t initialDstOffset() const;
+
+ /**
+ * Number of transitions in each time range
+ */
+ int16_t transitionCountPre32;
+ int16_t transitionCount32;
+ int16_t transitionCountPost32;
+
+ /**
+ * Time of each transition in seconds from 1970 epoch before 32bit second range (<= 1900).
+ * Each transition in this range is represented by a pair of int32_t.
+ * Length is transitionCount int32_t's. NULL if no transitions in this range.
+ */
+ const int32_t *transitionTimesPre32; // alias into res; do not delete
+
+ /**
+ * Time of each transition in seconds from 1970 epoch in 32bit second range.
+ * Length is transitionCount int32_t's. NULL if no transitions in this range.
+ */
+ const int32_t *transitionTimes32; // alias into res; do not delete
+
+ /**
+ * Time of each transition in seconds from 1970 epoch after 32bit second range (>= 2038).
+ * Each transition in this range is represented by a pair of int32_t.
+ * Length is transitionCount int32_t's. NULL if no transitions in this range.
+ */
+ const int32_t *transitionTimesPost32; // alias into res; do not delete
+
+ /**
+ * Number of types, 1..255
+ */
+ int16_t typeCount;
+
+ /**
+ * Offset from GMT in seconds for each type.
+ * Length is typeCount int32_t's. At least one type (a pair of int32_t)
+ * is required.
+ */
+ 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 int16_t's. NULL if no transitions.
+ */
+ const uint8_t *typeMapData; // alias into res; do not delete
+
+ /**
+ * A SimpleTimeZone that governs the behavior for date >= finalMillis.
+ */
+ SimpleTimeZone *finalZone; // owned, may be NULL
+
+ /**
+ * For date >= finalMillis, the finalZone will be used.
+ */
+ double finalStartMillis;
+
+ /**
+ * For year >= finalYear, the finalZone will be used.
+ */
+ int32_t finalStartYear;
+
+ /*
+ * Canonical (CLDR) ID of this zone
+ */
+ const UChar *canonicalID;
+
+ /* 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 int16_t
+OlsonTimeZone::transitionCount() const {
+ return transitionCountPre32 + transitionCount32 + transitionCountPost32;
+}
+
+inline double
+OlsonTimeZone::transitionTime(int16_t transIdx) const {
+ return (double)transitionTimeInSeconds(transIdx) * U_MILLIS_PER_SECOND;
+}
+
+inline int32_t
+OlsonTimeZone::zoneOffsetAt(int16_t transIdx) const {
+ int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1;
+ return typeOffsets[typeIdx] + typeOffsets[typeIdx + 1];
+}
+
+inline int32_t
+OlsonTimeZone::rawOffsetAt(int16_t transIdx) const {
+ int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1;
+ return typeOffsets[typeIdx];
+}
+
+inline int32_t
+OlsonTimeZone::dstOffsetAt(int16_t transIdx) const {
+ int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1;
+ return typeOffsets[typeIdx + 1];
+}
+
+inline int32_t
+OlsonTimeZone::initialRawOffset() const {
+ return typeOffsets[0];
+}
+
+inline int32_t
+OlsonTimeZone::initialDstOffset() const {
+ return typeOffsets[1];
+}
+
+inline const UChar*
+OlsonTimeZone::getCanonicalID() const {
+ return canonicalID;
+}
+
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // OLSONTZ_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/persncal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/persncal.cpp
new file mode 100644
index 00000000000..51303417aa9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/persncal.cpp
@@ -0,0 +1,465 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2003-2008, 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
+
+#include "umutex.h"
+#include <float.h>
+
+static const int8_t 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
+ { -5000000, -5000000, 5000000, 5000000}, // YEAR
+ { 0, 0, 11, 11}, // MONTH
+ { 1, 1, 52, 53}, // WEEK_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
+ { 1, 1, 29, 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
+ { -5000000, -5000000, 5000000, 5000000}, // 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
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
+};
+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);
+}
+
+// default century
+const UDate PersianCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t PersianCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate PersianCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t PersianCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+UBool PersianCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate PersianCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t PersianCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+PersianCalendar::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
+PersianCalendar::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
+PersianCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ UErrorCode status = U_ZERO_ERROR;
+ PersianCalendar calendar(Locale("@calendar=persian"),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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ umtx_unlock(NULL);
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar)
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/persncal.h b/Build/source/libs/icu/icu-4.8.1/i18n/persncal.h
new file mode 100644
index 00000000000..b926da5ef25
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/persncal.h
@@ -0,0 +1,364 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2003-2008, 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
+
+ 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 Persian 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-4.8.1/i18n/plurfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/plurfmt.cpp
new file mode 100644
index 00000000000..750f924fe0a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/plurfmt.cpp
@@ -0,0 +1,458 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+*******************************************************************************
+*/
+
+#include "unicode/messagepattern.h"
+#include "unicode/plurfmt.h"
+#include "unicode/plurrule.h"
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "messageimpl.h"
+#include "plurrule_impl.h"
+#include "uassert.h"
+#include "uhash.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+static const UChar OTHER_STRING[] = {
+ 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other"
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralFormat)
+
+PluralFormat::PluralFormat(UErrorCode& status)
+ : locale(Locale::getDefault()),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(NULL, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc, UErrorCode& status)
+ : locale(loc),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(NULL, status);
+}
+
+PluralFormat::PluralFormat(const PluralRules& rules, UErrorCode& status)
+ : locale(Locale::getDefault()),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(&rules, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc,
+ const PluralRules& rules,
+ UErrorCode& status)
+ : locale(loc),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(&rules, status);
+}
+
+PluralFormat::PluralFormat(const UnicodeString& pat,
+ UErrorCode& status)
+ : locale(Locale::getDefault()),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(NULL, status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc,
+ const UnicodeString& pat,
+ UErrorCode& status)
+ : locale(loc),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(NULL, status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const PluralRules& rules,
+ const UnicodeString& pat,
+ UErrorCode& status)
+ : locale(Locale::getDefault()),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(&rules, status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc,
+ const PluralRules& rules,
+ const UnicodeString& pat,
+ UErrorCode& status)
+ : locale(loc),
+ msgPattern(status),
+ numberFormat(NULL),
+ offset(0) {
+ init(&rules, status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const PluralFormat& other)
+ : Format(other),
+ locale(other.locale),
+ msgPattern(other.msgPattern),
+ numberFormat(NULL),
+ offset(other.offset) {
+ copyObjects(other);
+}
+
+void
+PluralFormat::copyObjects(const PluralFormat& other) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (numberFormat != NULL) {
+ delete numberFormat;
+ }
+ if (pluralRulesWrapper.pluralRules != NULL) {
+ delete pluralRulesWrapper.pluralRules;
+ }
+
+ if (other.numberFormat == NULL) {
+ numberFormat = NumberFormat::createInstance(locale, status);
+ } else {
+ numberFormat = (NumberFormat*)other.numberFormat->clone();
+ }
+ if (other.pluralRulesWrapper.pluralRules == NULL) {
+ pluralRulesWrapper.pluralRules = PluralRules::forLocale(locale, status);
+ } else {
+ pluralRulesWrapper.pluralRules = other.pluralRulesWrapper.pluralRules->clone();
+ }
+}
+
+
+PluralFormat::~PluralFormat() {
+ delete numberFormat;
+}
+
+void
+PluralFormat::init(const PluralRules* rules, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (rules==NULL) {
+ pluralRulesWrapper.pluralRules = PluralRules::forLocale(locale, status);
+ } else {
+ pluralRulesWrapper.pluralRules = rules->clone();
+ if (pluralRulesWrapper.pluralRules == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ numberFormat= NumberFormat::createInstance(locale, status);
+}
+
+void
+PluralFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
+ msgPattern.parsePluralStyle(newPattern, NULL, status);
+ if (U_FAILURE(status)) {
+ msgPattern.clear();
+ offset = 0;
+ return;
+ }
+ offset = msgPattern.getPluralOffset(0);
+}
+
+UnicodeString&
+PluralFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return appendTo;
+
+ if (obj.isNumeric()) {
+ return format(obj.getDouble(), appendTo, pos, status);
+ } else {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+}
+
+UnicodeString
+PluralFormat::format(int32_t number, UErrorCode& status) const {
+ FieldPosition fpos(0);
+ UnicodeString result;
+ return format(number, result, fpos, status);
+}
+
+UnicodeString
+PluralFormat::format(double number, UErrorCode& status) const {
+ FieldPosition fpos(0);
+ UnicodeString result;
+ return format(number, result, fpos, status);
+}
+
+
+UnicodeString&
+PluralFormat::format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const {
+ return format((double)number, appendTo, pos, status);
+}
+
+UnicodeString&
+PluralFormat::format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ if (msgPattern.countParts() == 0) {
+ return numberFormat->format(number, appendTo, pos);
+ }
+ // Get the appropriate sub-message.
+ int32_t partIndex = findSubMessage(msgPattern, 0, pluralRulesWrapper, number, status);
+ // Replace syntactic # signs in the top level of this sub-message
+ // (not in nested arguments) with the formatted number-offset.
+ const UnicodeString& pattern = msgPattern.getPatternString();
+ number -= offset;
+ int32_t prevIndex = msgPattern.getPart(partIndex).getLimit();
+ for (;;) {
+ const MessagePattern::Part& part = msgPattern.getPart(++partIndex);
+ const UMessagePatternPartType type = part.getType();
+ int32_t index = part.getIndex();
+ if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
+ return appendTo.append(pattern, prevIndex, index - prevIndex);
+ } else if ((type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) ||
+ (type == UMSGPAT_PART_TYPE_SKIP_SYNTAX && MessageImpl::jdkAposMode(msgPattern))) {
+ appendTo.append(pattern, prevIndex, index - prevIndex);
+ if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
+ numberFormat->format(number, appendTo);
+ }
+ prevIndex = part.getLimit();
+ } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
+ appendTo.append(pattern, prevIndex, index - prevIndex);
+ prevIndex = index;
+ partIndex = msgPattern.getLimitPartIndex(partIndex);
+ index = msgPattern.getPart(partIndex).getLimit();
+ MessageImpl::appendReducedApostrophes(pattern, prevIndex, index, appendTo);
+ prevIndex = index;
+ }
+ }
+}
+
+UnicodeString&
+PluralFormat::toPattern(UnicodeString& appendTo) {
+ if (0 == msgPattern.countParts()) {
+ appendTo.setToBogus();
+ } else {
+ appendTo.append(msgPattern.getPatternString());
+ }
+ return appendTo;
+}
+
+void
+PluralFormat::setLocale(const Locale& loc, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ locale = loc;
+ msgPattern.clear();
+ delete numberFormat;
+ offset = 0;
+ numberFormat = NULL;
+ pluralRulesWrapper.reset();
+ init(NULL, status);
+}
+
+void
+PluralFormat::setNumberFormat(const NumberFormat* format, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ NumberFormat* nf = (NumberFormat*)format->clone();
+ if (nf != NULL) {
+ delete numberFormat;
+ numberFormat = nf;
+ } else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+Format*
+PluralFormat::clone() const
+{
+ return new PluralFormat(*this);
+}
+
+
+PluralFormat&
+PluralFormat::operator=(const PluralFormat& other) {
+ if (this != &other) {
+ locale = other.locale;
+ msgPattern = other.msgPattern;
+ offset = other.offset;
+ copyObjects(other);
+ }
+
+ return *this;
+}
+
+UBool
+PluralFormat::operator==(const Format& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (!Format::operator==(other)) {
+ return FALSE;
+ }
+ const PluralFormat& o = (const PluralFormat&)other;
+ return
+ locale == o.locale &&
+ msgPattern == o.msgPattern && // implies same offset
+ (numberFormat == NULL) == (o.numberFormat == NULL) &&
+ (numberFormat == NULL || *numberFormat == *o.numberFormat) &&
+ (pluralRulesWrapper.pluralRules == NULL) == (o.pluralRulesWrapper.pluralRules == NULL) &&
+ (pluralRulesWrapper.pluralRules == NULL ||
+ *pluralRulesWrapper.pluralRules == *o.pluralRulesWrapper.pluralRules);
+}
+
+UBool
+PluralFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+void
+PluralFormat::parseObject(const UnicodeString& /*source*/,
+ Formattable& /*result*/,
+ ParsePosition& pos) const
+{
+ // Parsing not supported.
+ pos.setErrorIndex(pos.getIndex());
+}
+
+int32_t PluralFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex,
+ const PluralSelector& selector, double number, UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return 0;
+ }
+ int32_t count=pattern.countParts();
+ double offset;
+ const MessagePattern::Part* part=&pattern.getPart(partIndex);
+ if (MessagePattern::Part::hasNumericValue(part->getType())) {
+ offset=pattern.getNumericValue(*part);
+ ++partIndex;
+ } else {
+ offset=0;
+ }
+ // The keyword is empty until we need to match against non-explicit, not-"other" value.
+ // Then we get the keyword from the selector.
+ // (In other words, we never call the selector if we match against an explicit value,
+ // or if the only non-explicit keyword is "other".)
+ UnicodeString keyword;
+ UnicodeString other(FALSE, OTHER_STRING, 5);
+ // When we find a match, we set msgStart>0 and also set this boolean to true
+ // to avoid matching the keyword again (duplicates are allowed)
+ // while we continue to look for an explicit-value match.
+ UBool haveKeywordMatch=FALSE;
+ // msgStart is 0 until we find any appropriate sub-message.
+ // We remember the first "other" sub-message if we have not seen any
+ // appropriate sub-message before.
+ // We remember the first matching-keyword sub-message if we have not seen
+ // one of those before.
+ // (The parser allows [does not check for] duplicate keywords.
+ // We just have to make sure to take the first one.)
+ // We avoid matching the keyword twice by also setting haveKeywordMatch=true
+ // at the first keyword match.
+ // We keep going until we find an explicit-value match or reach the end of the plural style.
+ int32_t msgStart=0;
+ // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
+ // until ARG_LIMIT or end of plural-only pattern.
+ do {
+ part=&pattern.getPart(partIndex++);
+ const UMessagePatternPartType type = part->getType();
+ if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
+ break;
+ }
+ U_ASSERT (type==UMSGPAT_PART_TYPE_ARG_SELECTOR);
+ // part is an ARG_SELECTOR followed by an optional explicit value, and then a message
+ if(MessagePattern::Part::hasNumericValue(pattern.getPartType(partIndex))) {
+ // explicit value like "=2"
+ part=&pattern.getPart(partIndex++);
+ if(number==pattern.getNumericValue(*part)) {
+ // matches explicit value
+ return partIndex;
+ }
+ } else if(!haveKeywordMatch) {
+ // plural keyword like "few" or "other"
+ // Compare "other" first and call the selector if this is not "other".
+ if(pattern.partSubstringMatches(*part, other)) {
+ if(msgStart==0) {
+ msgStart=partIndex;
+ if(0 == keyword.compare(other)) {
+ // This is the first "other" sub-message,
+ // and the selected keyword is also "other".
+ // Do not match "other" again.
+ haveKeywordMatch=TRUE;
+ }
+ }
+ } else {
+ if(keyword.isEmpty()) {
+ keyword=selector.select(number-offset, ec);
+ if(msgStart!=0 && (0 == keyword.compare(other))) {
+ // We have already seen an "other" sub-message.
+ // Do not match "other" again.
+ haveKeywordMatch=TRUE;
+ // Skip keyword matching but do getLimitPartIndex().
+ }
+ }
+ if(!haveKeywordMatch && pattern.partSubstringMatches(*part, keyword)) {
+ // keyword matches
+ msgStart=partIndex;
+ // Do not match this keyword again.
+ haveKeywordMatch=TRUE;
+ }
+ }
+ }
+ partIndex=pattern.getLimitPartIndex(partIndex);
+ } while(++partIndex<count);
+ return msgStart;
+}
+
+PluralFormat::PluralSelectorAdapter::~PluralSelectorAdapter() {
+ delete pluralRules;
+}
+
+UnicodeString PluralFormat::PluralSelectorAdapter::select(double number,
+ UErrorCode& /*ec*/) const {
+ return pluralRules->select(number);
+}
+
+void PluralFormat::PluralSelectorAdapter::reset() {
+ delete pluralRules;
+ pluralRules = NULL;
+}
+
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/plurrule.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/plurrule.cpp
new file mode 100644
index 00000000000..98aec26ad5f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/plurrule.cpp
@@ -0,0 +1,1432 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURRULE.CPP
+*
+* Modification History:
+*
+* Date Name Description
+*******************************************************************************
+*/
+
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+#include "unicode/plurrule.h"
+#include "unicode/ures.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "hash.h"
+#include "mutex.h"
+#include "patternprops.h"
+#include "plurrule_impl.h"
+#include "putilimp.h"
+#include "ucln_in.h"
+#include "uhash.h"
+#include "ustrfmt.h"
+#include "locutil.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+// shared by all instances when lazy-initializing samples
+static UMTX pluralMutex;
+
+#define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
+
+static const UChar PLURAL_KEYWORD_OTHER[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,0};
+static const UChar PLURAL_DEFAULT_RULE[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,COLON,SPACE,LOW_N,0};
+static const UChar PK_IN[]={LOW_I,LOW_N,0};
+static const UChar PK_NOT[]={LOW_N,LOW_O,LOW_T,0};
+static const UChar PK_IS[]={LOW_I,LOW_S,0};
+static const UChar PK_MOD[]={LOW_M,LOW_O,LOW_D,0};
+static const UChar PK_AND[]={LOW_A,LOW_N,LOW_D,0};
+static const UChar PK_OR[]={LOW_O,LOW_R,0};
+static const UChar PK_VAR_N[]={LOW_N,0};
+static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
+
+PluralRules::PluralRules(UErrorCode& status)
+: UObject(),
+ mRules(NULL),
+ mParser(NULL),
+ mSamples(NULL),
+ mSampleInfo(NULL),
+ mSampleInfoCount(0)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ mParser = new RuleParser();
+ if (mParser==NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+PluralRules::PluralRules(const PluralRules& other)
+: UObject(other),
+ mRules(NULL),
+ mParser(NULL),
+ mSamples(NULL),
+ mSampleInfo(NULL),
+ mSampleInfoCount(0)
+{
+ *this=other;
+}
+
+PluralRules::~PluralRules() {
+ delete mRules;
+ delete mParser;
+ uprv_free(mSamples);
+ uprv_free(mSampleInfo);
+}
+
+PluralRules*
+PluralRules::clone() const {
+ return new PluralRules(*this);
+}
+
+PluralRules&
+PluralRules::operator=(const PluralRules& other) {
+ if (this != &other) {
+ delete mRules;
+ if (other.mRules==NULL) {
+ mRules = NULL;
+ }
+ else {
+ mRules = new RuleChain(*other.mRules);
+ }
+ delete mParser;
+ mParser = new RuleParser();
+
+ uprv_free(mSamples);
+ mSamples = NULL;
+
+ uprv_free(mSampleInfo);
+ mSampleInfo = NULL;
+ mSampleInfoCount = 0;
+ }
+
+ return *this;
+}
+
+PluralRules* U_EXPORT2
+PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
+ RuleChain rules;
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ PluralRules *newRules = new PluralRules(status);
+ if ( (newRules != NULL)&& U_SUCCESS(status) ) {
+ newRules->parseDescription((UnicodeString &)description, rules, status);
+ if (U_SUCCESS(status)) {
+ newRules->addRules(rules);
+ }
+ }
+ if (U_FAILURE(status)) {
+ delete newRules;
+ return NULL;
+ }
+ else {
+ return newRules;
+ }
+}
+
+PluralRules* U_EXPORT2
+PluralRules::createDefaultRules(UErrorCode& status) {
+ return createRules(PLURAL_DEFAULT_RULE, status);
+}
+
+PluralRules* U_EXPORT2
+PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
+ RuleChain rChain;
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ PluralRules *newObj = new PluralRules(status);
+ if (newObj==NULL || U_FAILURE(status)) {
+ delete newObj;
+ return NULL;
+ }
+ UnicodeString locRule = newObj->getRuleFromResource(locale, status);
+ if ((locRule.length() != 0) && U_SUCCESS(status)) {
+ newObj->parseDescription(locRule, rChain, status);
+ if (U_SUCCESS(status)) {
+ newObj->addRules(rChain);
+ }
+ }
+ if (U_FAILURE(status)||(locRule.length() == 0)) {
+ // use default plural rule
+ status = U_ZERO_ERROR;
+ UnicodeString defRule = UnicodeString(PLURAL_DEFAULT_RULE);
+ newObj->parseDescription(defRule, rChain, status);
+ newObj->addRules(rChain);
+ }
+
+ return newObj;
+}
+
+UnicodeString
+PluralRules::select(int32_t number) const {
+ if (mRules == NULL) {
+ return PLURAL_DEFAULT_RULE;
+ }
+ else {
+ return mRules->select(number);
+ }
+}
+
+UnicodeString
+PluralRules::select(double number) const {
+ if (mRules == NULL) {
+ return PLURAL_DEFAULT_RULE;
+ }
+ else {
+ return mRules->select(number);
+ }
+}
+
+StringEnumeration*
+PluralRules::getKeywords(UErrorCode& status) const {
+ if (U_FAILURE(status)) return NULL;
+ StringEnumeration* nameEnumerator = new PluralKeywordEnumeration(mRules, status);
+ if (U_FAILURE(status)) {
+ delete nameEnumerator;
+ return NULL;
+ }
+
+ return nameEnumerator;
+}
+
+double
+PluralRules::getUniqueKeywordValue(const UnicodeString& keyword) {
+ double val = 0.0;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t count = getSamplesInternal(keyword, &val, 1, FALSE, status);
+ return count == 1 ? val : UPLRULES_NO_UNIQUE_VALUE;
+}
+
+int32_t
+PluralRules::getAllKeywordValues(const UnicodeString &keyword, double *dest,
+ int32_t destCapacity, UErrorCode& error) {
+ return getSamplesInternal(keyword, dest, destCapacity, FALSE, error);
+}
+
+int32_t
+PluralRules::getSamples(const UnicodeString &keyword, double *dest,
+ int32_t destCapacity, UErrorCode& status) {
+ return getSamplesInternal(keyword, dest, destCapacity, TRUE, status);
+}
+
+int32_t
+PluralRules::getSamplesInternal(const UnicodeString &keyword, double *dest,
+ int32_t destCapacity, UBool includeUnlimited,
+ UErrorCode& status) {
+ initSamples(status);
+ if (U_FAILURE(status)) {
+ return -1;
+ }
+ if (destCapacity < 0 || (dest == NULL && destCapacity > 0)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ int32_t index = getKeywordIndex(keyword, status);
+ if (index == -1) {
+ return 0;
+ }
+
+ const int32_t LIMIT_MASK = 0x1 << 31;
+
+ if (!includeUnlimited) {
+ if ((mSampleInfo[index] & LIMIT_MASK) == 0) {
+ return -1;
+ }
+ }
+
+ int32_t start = index == 0 ? 0 : mSampleInfo[index - 1] & ~LIMIT_MASK;
+ int32_t limit = mSampleInfo[index] & ~LIMIT_MASK;
+ int32_t len = limit - start;
+ if (len <= destCapacity) {
+ destCapacity = len;
+ } else if (includeUnlimited) {
+ len = destCapacity; // no overflow, and don't report more than we copy
+ } else {
+ status = U_BUFFER_OVERFLOW_ERROR;
+ return len;
+ }
+ for (int32_t i = 0; i < destCapacity; ++i, ++start) {
+ dest[i] = mSamples[start];
+ }
+ return len;
+}
+
+
+UBool
+PluralRules::isKeyword(const UnicodeString& keyword) const {
+ if ( keyword == PLURAL_KEYWORD_OTHER ) {
+ return true;
+ }
+ else {
+ if (mRules==NULL) {
+ return false;
+ }
+ else {
+ return mRules->isKeyword(keyword);
+ }
+ }
+}
+
+UnicodeString
+PluralRules::getKeywordOther() const {
+ return PLURAL_KEYWORD_OTHER;
+}
+
+UBool
+PluralRules::operator==(const PluralRules& other) const {
+ int32_t limit;
+ const UnicodeString *ptrKeyword;
+ UErrorCode status= U_ZERO_ERROR;
+
+ if ( this == &other ) {
+ return TRUE;
+ }
+ LocalPointer<StringEnumeration> myKeywordList(getKeywords(status));
+ LocalPointer<StringEnumeration> otherKeywordList(other.getKeywords(status));
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ if (myKeywordList->count(status)!=otherKeywordList->count(status)) {
+ return FALSE;
+ }
+ myKeywordList->reset(status);
+ while ((ptrKeyword=myKeywordList->snext(status))!=NULL) {
+ if (!other.isKeyword(*ptrKeyword)) {
+ return FALSE;
+ }
+ }
+ otherKeywordList->reset(status);
+ while ((ptrKeyword=otherKeywordList->snext(status))!=NULL) {
+ if (!this->isKeyword(*ptrKeyword)) {
+ return FALSE;
+ }
+ }
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ if ((limit=this->getRepeatLimit()) != other.getRepeatLimit()) {
+ return FALSE;
+ }
+ UnicodeString myKeyword, otherKeyword;
+ for (int32_t i=0; i<limit; ++i) {
+ myKeyword = this->select(i);
+ otherKeyword = other.select(i);
+ if (myKeyword!=otherKeyword) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void
+PluralRules::parseDescription(UnicodeString& data, RuleChain& rules, UErrorCode &status)
+{
+ int32_t ruleIndex=0;
+ UnicodeString token;
+ tokenType type;
+ tokenType prevType=none;
+ RuleChain *ruleChain=NULL;
+ AndConstraint *curAndConstraint=NULL;
+ OrConstraint *orNode=NULL;
+ RuleChain *lastChain=NULL;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UnicodeString ruleData = data.toLower();
+ while (ruleIndex< ruleData.length()) {
+ mParser->getNextToken(ruleData, &ruleIndex, token, type, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ mParser->checkSyntax(prevType, type, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ switch (type) {
+ case tAnd:
+ curAndConstraint = curAndConstraint->add();
+ break;
+ case tOr:
+ lastChain = &rules;
+ while (lastChain->next !=NULL) {
+ lastChain = lastChain->next;
+ }
+ orNode=lastChain->ruleHeader;
+ while (orNode->next != NULL) {
+ orNode = orNode->next;
+ }
+ orNode->next= new OrConstraint();
+ orNode=orNode->next;
+ orNode->next=NULL;
+ curAndConstraint = orNode->add();
+ break;
+ case tIs:
+ curAndConstraint->rangeHigh=-1;
+ break;
+ case tNot:
+ curAndConstraint->notIn=TRUE;
+ break;
+ case tIn:
+ curAndConstraint->rangeHigh=PLURAL_RANGE_HIGH;
+ curAndConstraint->integerOnly = TRUE;
+ break;
+ case tWithin:
+ curAndConstraint->rangeHigh=PLURAL_RANGE_HIGH;
+ break;
+ case tNumber:
+ if ( (curAndConstraint->op==AndConstraint::MOD)&&
+ (curAndConstraint->opNum == -1 ) ) {
+ curAndConstraint->opNum=getNumberValue(token);
+ }
+ else {
+ if (curAndConstraint->rangeLow == -1) {
+ curAndConstraint->rangeLow=getNumberValue(token);
+ }
+ else {
+ curAndConstraint->rangeHigh=getNumberValue(token);
+ }
+ }
+ break;
+ case tMod:
+ curAndConstraint->op=AndConstraint::MOD;
+ break;
+ case tKeyword:
+ if (ruleChain==NULL) {
+ ruleChain = &rules;
+ }
+ else {
+ while (ruleChain->next!=NULL){
+ ruleChain=ruleChain->next;
+ }
+ ruleChain=ruleChain->next=new RuleChain();
+ }
+ if (ruleChain->ruleHeader != NULL) {
+ delete ruleChain->ruleHeader;
+ }
+ orNode = ruleChain->ruleHeader = new OrConstraint();
+ curAndConstraint = orNode->add();
+ ruleChain->keyword = token;
+ break;
+ default:
+ break;
+ }
+ prevType=type;
+ }
+}
+
+int32_t
+PluralRules::getNumberValue(const UnicodeString& token) const {
+ int32_t i;
+ char digits[128];
+
+ i = token.extract(0, token.length(), digits, ARRAY_SIZE(digits), US_INV);
+ digits[i]='\0';
+
+ return((int32_t)atoi(digits));
+}
+
+
+void
+PluralRules::getNextLocale(const UnicodeString& localeData, int32_t* curIndex, UnicodeString& localeName) {
+ int32_t i=*curIndex;
+
+ localeName.remove();
+ while (i< localeData.length()) {
+ if ( (localeData.charAt(i)!= SPACE) && (localeData.charAt(i)!= COMMA) ) {
+ break;
+ }
+ i++;
+ }
+
+ while (i< localeData.length()) {
+ if ( (localeData.charAt(i)== SPACE) || (localeData.charAt(i)== COMMA) ) {
+ break;
+ }
+ localeName+=localeData.charAt(i++);
+ }
+ *curIndex=i;
+}
+
+
+int32_t
+PluralRules::getRepeatLimit() const {
+ if (mRules!=NULL) {
+ return mRules->getRepeatLimit();
+ }
+ else {
+ return 0;
+ }
+}
+
+int32_t
+PluralRules::getKeywordIndex(const UnicodeString& keyword,
+ UErrorCode& status) const {
+ if (U_SUCCESS(status)) {
+ int32_t n = 0;
+ RuleChain* rc = mRules;
+ while (rc != NULL) {
+ if (rc->ruleHeader != NULL) {
+ if (rc->keyword == keyword) {
+ return n;
+ }
+ ++n;
+ }
+ rc = rc->next;
+ }
+ if (keyword == PLURAL_KEYWORD_OTHER) {
+ return n;
+ }
+ }
+ return -1;
+}
+
+typedef struct SampleRecord {
+ int32_t ruleIndex;
+ double value;
+} SampleRecord;
+
+void
+PluralRules::initSamples(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ Mutex lock(&pluralMutex);
+
+ if (mSamples) {
+ return;
+ }
+
+ // Note, the original design let you have multiple rules with the same keyword. But
+ // we don't use that in our data and existing functions in this implementation don't
+ // fully support it (for example, the returned keywords is a list and not a set).
+ //
+ // So I don't support this here either. If you ask for samples, or for all values,
+ // you will get information about the first rule with that keyword, not all rules with
+ // that keyword.
+
+ int32_t maxIndex = 0;
+ int32_t otherIndex = -1; // the value -1 will indicate we added 'other' at end
+ RuleChain* rc = mRules;
+ while (rc != NULL) {
+ if (rc->ruleHeader != NULL) {
+ if (otherIndex == -1 && rc->keyword == PLURAL_KEYWORD_OTHER) {
+ otherIndex = maxIndex;
+ }
+ ++maxIndex;
+ }
+ rc = rc->next;
+ }
+ if (otherIndex == -1) {
+ ++maxIndex;
+ }
+
+ LocalMemory<int32_t> newSampleInfo;
+ if (NULL == newSampleInfo.allocateInsteadAndCopy(maxIndex)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ const int32_t LIMIT_MASK = 0x1 << 31;
+
+ rc = mRules;
+ int32_t n = 0;
+ while (rc != NULL) {
+ if (rc->ruleHeader != NULL) {
+ newSampleInfo[n++] = rc->ruleHeader->isLimited() ? LIMIT_MASK : 0;
+ }
+ rc = rc->next;
+ }
+ if (otherIndex == -1) {
+ newSampleInfo[maxIndex - 1] = 0; // unlimited
+ }
+
+ MaybeStackArray<SampleRecord, 10> newSamples;
+ int32_t sampleCount = 0;
+
+ int32_t limit = getRepeatLimit() * MAX_SAMPLES * 2;
+ if (limit < 10) {
+ limit = 10;
+ }
+
+ for (int i = 0, keywordsRemaining = maxIndex;
+ keywordsRemaining > 0 && i < limit;
+ ++i) {
+ double val = i / 2.0;
+
+ n = 0;
+ rc = mRules;
+ int32_t found = -1;
+ while (rc != NULL) {
+ if (rc->ruleHeader != NULL) {
+ if (rc->ruleHeader->isFulfilled(val)) {
+ found = n;
+ break;
+ }
+ ++n;
+ }
+ rc = rc->next;
+ }
+ if (found == -1) {
+ // 'other'. If there is an 'other' rule, the rule set is bad since nothing
+ // should leak through, but we don't bother to report that here.
+ found = otherIndex == -1 ? maxIndex - 1 : otherIndex;
+ }
+ if (newSampleInfo[found] == MAX_SAMPLES) { // limit flag not set
+ continue;
+ }
+ newSampleInfo[found] += 1; // won't impact limit flag
+
+ if (sampleCount == newSamples.getCapacity()) {
+ int32_t newCapacity = sampleCount < 20 ? 128 : sampleCount * 2;
+ if (NULL == newSamples.resize(newCapacity, sampleCount)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ newSamples[sampleCount].ruleIndex = found;
+ newSamples[sampleCount].value = val;
+ ++sampleCount;
+
+ if (newSampleInfo[found] == MAX_SAMPLES) { // limit flag not set
+ --keywordsRemaining;
+ }
+ }
+
+ // sort the values by index, leaving order otherwise unchanged
+ // this is just a selection sort for simplicity
+ LocalMemory<double> values;
+ if (NULL == values.allocateInsteadAndCopy(sampleCount)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (int i = 0, j = 0; i < maxIndex; ++i) {
+ for (int k = 0; k < sampleCount; ++k) {
+ if (newSamples[k].ruleIndex == i) {
+ values[j++] = newSamples[k].value;
+ }
+ }
+ }
+
+ // convert array of mask/lengths to array of mask/limits
+ limit = 0;
+ for (int i = 0; i < maxIndex; ++i) {
+ int32_t info = newSampleInfo[i];
+ int32_t len = info & ~LIMIT_MASK;
+ limit += len;
+ // if a rule is 'unlimited' but has fewer than MAX_SAMPLES samples,
+ // it's not really unlimited, so mark it as limited
+ int32_t mask = len < MAX_SAMPLES ? LIMIT_MASK : info & LIMIT_MASK;
+ newSampleInfo[i] = limit | mask;
+ }
+
+ // ok, we've got good data
+ mSamples = values.orphan();
+ mSampleInfo = newSampleInfo.orphan();
+ mSampleInfoCount = maxIndex;
+}
+
+void
+PluralRules::addRules(RuleChain& rules) {
+ RuleChain *newRule = new RuleChain(rules);
+ this->mRules=newRule;
+ newRule->setRepeatLimit();
+}
+
+UnicodeString
+PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
+ UnicodeString emptyStr;
+
+ if (U_FAILURE(errCode)) {
+ return emptyStr;
+ }
+ UResourceBundle *rb=ures_openDirect(NULL, "plurals", &errCode);
+ if(U_FAILURE(errCode)) {
+ /* total failure, not even root could be opened */
+ return emptyStr;
+ }
+ UResourceBundle *locRes=ures_getByKey(rb, "locales", NULL, &errCode);
+ if(U_FAILURE(errCode)) {
+ ures_close(rb);
+ return emptyStr;
+ }
+ int32_t resLen=0;
+ const char *curLocaleName=locale.getName();
+ const UChar* s = ures_getStringByKey(locRes, curLocaleName, &resLen, &errCode);
+
+ if (s == NULL) {
+ // Check parent locales.
+ UErrorCode status = U_ZERO_ERROR;
+ char parentLocaleName[ULOC_FULLNAME_CAPACITY];
+ const char *curLocaleName=locale.getName();
+ int32_t localeNameLen=0;
+ uprv_strcpy(parentLocaleName, curLocaleName);
+
+ while ((localeNameLen=uloc_getParent(parentLocaleName, parentLocaleName,
+ ULOC_FULLNAME_CAPACITY, &status)) > 0) {
+ resLen=0;
+ s = ures_getStringByKey(locRes, parentLocaleName, &resLen, &status);
+ if (s != NULL) {
+ errCode = U_ZERO_ERROR;
+ break;
+ }
+ status = U_ZERO_ERROR;
+ }
+ }
+ if (s==NULL) {
+ ures_close(locRes);
+ ures_close(rb);
+ return emptyStr;
+ }
+
+ char setKey[256];
+ UChar result[256];
+ u_UCharsToChars(s, setKey, resLen + 1);
+ // printf("\n PluralRule: %s\n", setKey);
+
+
+ UResourceBundle *ruleRes=ures_getByKey(rb, "rules", NULL, &errCode);
+ if(U_FAILURE(errCode)) {
+ ures_close(locRes);
+ ures_close(rb);
+ return emptyStr;
+ }
+ resLen=0;
+ UResourceBundle *setRes = ures_getByKey(ruleRes, setKey, NULL, &errCode);
+ if (U_FAILURE(errCode)) {
+ ures_close(ruleRes);
+ ures_close(locRes);
+ ures_close(rb);
+ return emptyStr;
+ }
+
+ int32_t numberKeys = ures_getSize(setRes);
+ char *key=NULL;
+ int32_t len=0;
+ for(int32_t i=0; i<numberKeys; ++i) {
+ int32_t keyLen;
+ resLen=0;
+ s=ures_getNextString(setRes, &resLen, (const char**)&key, &errCode);
+ keyLen = (int32_t)uprv_strlen(key);
+ u_charsToUChars(key, result+len, keyLen);
+ len += keyLen;
+ result[len++]=COLON;
+ uprv_memcpy(result+len, s, resLen*sizeof(UChar));
+ len += resLen;
+ result[len++]=SEMI_COLON;
+ }
+ result[len++]=0;
+ u_UCharsToChars(result, setKey, len);
+ // printf(" Rule: %s\n", setKey);
+
+ ures_close(setRes);
+ ures_close(ruleRes);
+ ures_close(locRes);
+ ures_close(rb);
+ return UnicodeString(result);
+}
+
+AndConstraint::AndConstraint() {
+ op = AndConstraint::NONE;
+ opNum=-1;
+ rangeLow=-1;
+ rangeHigh=-1;
+ notIn=FALSE;
+ integerOnly=FALSE;
+ next=NULL;
+}
+
+
+AndConstraint::AndConstraint(const AndConstraint& other) {
+ this->op = other.op;
+ this->opNum=other.opNum;
+ this->rangeLow=other.rangeLow;
+ this->rangeHigh=other.rangeHigh;
+ this->integerOnly=other.integerOnly;
+ this->notIn=other.notIn;
+ if (other.next==NULL) {
+ this->next=NULL;
+ }
+ else {
+ this->next = new AndConstraint(*other.next);
+ }
+}
+
+AndConstraint::~AndConstraint() {
+ if (next!=NULL) {
+ delete next;
+ }
+}
+
+
+UBool
+AndConstraint::isFulfilled(double number) {
+ UBool result=TRUE;
+ double value=number;
+
+ // arrrrrrgh
+ if ((rangeHigh == -1 || integerOnly) && number != uprv_floor(number)) {
+ return notIn;
+ }
+
+ if ( op == MOD ) {
+ value = (int32_t)value % opNum;
+ }
+ if ( rangeHigh == -1 ) {
+ if ( rangeLow == -1 ) {
+ result = TRUE; // empty rule
+ }
+ else {
+ if ( value == rangeLow ) {
+ result = TRUE;
+ }
+ else {
+ result = FALSE;
+ }
+ }
+ }
+ else {
+ if ((rangeLow <= value) && (value <= rangeHigh)) {
+ if (integerOnly) {
+ if ( value != (int32_t)value) {
+ result = FALSE;
+ }
+ else {
+ result = TRUE;
+ }
+ }
+ else {
+ result = TRUE;
+ }
+ }
+ else {
+ result = FALSE;
+ }
+ }
+ if (notIn) {
+ return !result;
+ }
+ else {
+ return result;
+ }
+}
+
+UBool
+AndConstraint::isLimited() {
+ return (rangeHigh == -1 || integerOnly) && !notIn && op != MOD;
+}
+
+int32_t
+AndConstraint::updateRepeatLimit(int32_t maxLimit) {
+
+ if ( op == MOD ) {
+ return uprv_max(opNum, maxLimit);
+ }
+ else {
+ if ( rangeHigh == -1 ) {
+ return uprv_max(rangeLow, maxLimit);
+ }
+ else{
+ return uprv_max(rangeHigh, maxLimit);
+ }
+ }
+}
+
+
+AndConstraint*
+AndConstraint::add()
+{
+ this->next = new AndConstraint();
+ return this->next;
+}
+
+OrConstraint::OrConstraint() {
+ childNode=NULL;
+ next=NULL;
+}
+
+OrConstraint::OrConstraint(const OrConstraint& other) {
+ if ( other.childNode == NULL ) {
+ this->childNode = NULL;
+ }
+ else {
+ this->childNode = new AndConstraint(*(other.childNode));
+ }
+ if (other.next == NULL ) {
+ this->next = NULL;
+ }
+ else {
+ this->next = new OrConstraint(*(other.next));
+ }
+}
+
+OrConstraint::~OrConstraint() {
+ if (childNode!=NULL) {
+ delete childNode;
+ }
+ if (next!=NULL) {
+ delete next;
+ }
+}
+
+AndConstraint*
+OrConstraint::add()
+{
+ OrConstraint *curOrConstraint=this;
+ {
+ while (curOrConstraint->next!=NULL) {
+ curOrConstraint = curOrConstraint->next;
+ }
+ curOrConstraint->next = NULL;
+ curOrConstraint->childNode = new AndConstraint();
+ }
+ return curOrConstraint->childNode;
+}
+
+UBool
+OrConstraint::isFulfilled(double number) {
+ OrConstraint* orRule=this;
+ UBool result=FALSE;
+
+ while (orRule!=NULL && !result) {
+ result=TRUE;
+ AndConstraint* andRule = orRule->childNode;
+ while (andRule!=NULL && result) {
+ result = andRule->isFulfilled(number);
+ andRule=andRule->next;
+ }
+ orRule = orRule->next;
+ }
+
+ return result;
+}
+
+UBool
+OrConstraint::isLimited() {
+ for (OrConstraint *orc = this; orc != NULL; orc = orc->next) {
+ UBool result = FALSE;
+ for (AndConstraint *andc = orc->childNode; andc != NULL; andc = andc->next) {
+ if (andc->isLimited()) {
+ result = TRUE;
+ break;
+ }
+ }
+ if (result == FALSE) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+RuleChain::RuleChain() {
+ ruleHeader=NULL;
+ next = NULL;
+ repeatLimit=0;
+}
+
+RuleChain::RuleChain(const RuleChain& other) {
+ this->repeatLimit = other.repeatLimit;
+ this->keyword=other.keyword;
+ if (other.ruleHeader != NULL) {
+ this->ruleHeader = new OrConstraint(*(other.ruleHeader));
+ }
+ else {
+ this->ruleHeader = NULL;
+ }
+ if (other.next != NULL ) {
+ this->next = new RuleChain(*other.next);
+ }
+ else
+ {
+ this->next = NULL;
+ }
+}
+
+RuleChain::~RuleChain() {
+ if (next != NULL) {
+ delete next;
+ }
+ if ( ruleHeader != NULL ) {
+ delete ruleHeader;
+ }
+}
+
+UnicodeString
+RuleChain::select(double number) const {
+
+ if ( ruleHeader != NULL ) {
+ if (ruleHeader->isFulfilled(number)) {
+ return keyword;
+ }
+ }
+ if ( next != NULL ) {
+ return next->select(number);
+ }
+ else {
+ return PLURAL_KEYWORD_OTHER;
+ }
+
+}
+
+void
+RuleChain::dumpRules(UnicodeString& result) {
+ UChar digitString[16];
+
+ if ( ruleHeader != NULL ) {
+ result += keyword;
+ OrConstraint* orRule=ruleHeader;
+ while ( orRule != NULL ) {
+ AndConstraint* andRule=orRule->childNode;
+ while ( andRule != NULL ) {
+ if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeHigh==-1) ) {
+ result += UNICODE_STRING_SIMPLE(" n is ");
+ if (andRule->notIn) {
+ result += UNICODE_STRING_SIMPLE("not ");
+ }
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ if (andRule->op==AndConstraint::MOD) {
+ result += UNICODE_STRING_SIMPLE(" n mod ");
+ uprv_itou(digitString,16, andRule->opNum,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" n ");
+ }
+ if (andRule->rangeHigh==-1) {
+ if (andRule->notIn) {
+ result += UNICODE_STRING_SIMPLE(" is not ");
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" is ");
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ }
+ }
+ else {
+ if (andRule->notIn) {
+ if ( andRule->integerOnly ) {
+ result += UNICODE_STRING_SIMPLE(" not in ");
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" not within ");
+ }
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ result += UNICODE_STRING_SIMPLE(" .. ");
+ uprv_itou(digitString,16, andRule->rangeHigh,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ if ( andRule->integerOnly ) {
+ result += UNICODE_STRING_SIMPLE(" in ");
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" within ");
+ }
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ result += UNICODE_STRING_SIMPLE(" .. ");
+ uprv_itou(digitString,16, andRule->rangeHigh,10,0);
+ }
+ }
+ }
+ if ( (andRule=andRule->next) != NULL) {
+ result += PK_AND;
+ }
+ }
+ if ( (orRule = orRule->next) != NULL ) {
+ result += PK_OR;
+ }
+ }
+ }
+ if ( next != NULL ) {
+ next->dumpRules(result);
+ }
+}
+
+int32_t
+RuleChain::getRepeatLimit () {
+ return repeatLimit;
+}
+
+void
+RuleChain::setRepeatLimit () {
+ int32_t limit=0;
+
+ if ( next != NULL ) {
+ next->setRepeatLimit();
+ limit = next->repeatLimit;
+ }
+
+ if ( ruleHeader != NULL ) {
+ OrConstraint* orRule=ruleHeader;
+ while ( orRule != NULL ) {
+ AndConstraint* andRule=orRule->childNode;
+ while ( andRule != NULL ) {
+ limit = andRule->updateRepeatLimit(limit);
+ andRule = andRule->next;
+ }
+ orRule = orRule->next;
+ }
+ }
+ repeatLimit = limit;
+}
+
+UErrorCode
+RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
+ if ( arraySize < capacityOfKeywords-1 ) {
+ keywords[arraySize++]=keyword;
+ }
+ else {
+ return U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ if ( next != NULL ) {
+ return next->getKeywords(capacityOfKeywords, keywords, arraySize);
+ }
+ else {
+ return U_ZERO_ERROR;
+ }
+}
+
+UBool
+RuleChain::isKeyword(const UnicodeString& keywordParam) const {
+ if ( keyword == keywordParam ) {
+ return TRUE;
+ }
+
+ if ( next != NULL ) {
+ return next->isKeyword(keywordParam);
+ }
+ else {
+ return FALSE;
+ }
+}
+
+
+RuleParser::RuleParser() {
+}
+
+RuleParser::~RuleParser() {
+}
+
+void
+RuleParser::checkSyntax(tokenType prevType, tokenType curType, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ switch(prevType) {
+ case none:
+ case tSemiColon:
+ if (curType!=tKeyword) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tVariableN :
+ if (curType != tIs && curType != tMod && curType != tIn &&
+ curType != tNot && curType != tWithin) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tZero:
+ case tOne:
+ case tTwo:
+ case tFew:
+ case tMany:
+ case tOther:
+ case tKeyword:
+ if (curType != tColon) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tColon :
+ if (curType != tVariableN) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tIs:
+ if ( curType != tNumber && curType != tNot) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tNot:
+ if (curType != tNumber && curType != tIn && curType != tWithin) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tMod:
+ case tDot:
+ case tIn:
+ case tWithin:
+ case tAnd:
+ case tOr:
+ if (curType != tNumber && curType != tVariableN) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tNumber:
+ if (curType != tDot && curType != tSemiColon && curType != tIs && curType != tNot &&
+ curType != tIn && curType != tWithin && curType != tAnd && curType != tOr)
+ {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ default:
+ status = U_UNEXPECTED_TOKEN;
+ break;
+ }
+}
+
+void
+RuleParser::getNextToken(const UnicodeString& ruleData,
+ int32_t *ruleIndex,
+ UnicodeString& token,
+ tokenType& type,
+ UErrorCode &status)
+{
+ int32_t curIndex= *ruleIndex;
+ UChar ch;
+ tokenType prevType=none;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ while (curIndex<ruleData.length()) {
+ ch = ruleData.charAt(curIndex);
+ if ( !inRange(ch, type) ) {
+ status = U_ILLEGAL_CHARACTER;
+ return;
+ }
+ switch (type) {
+ case tSpace:
+ if ( *ruleIndex != curIndex ) { // letter
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ *ruleIndex=curIndex;
+ type=prevType;
+ getKeyType(token, type, status);
+ return;
+ }
+ else {
+ *ruleIndex=*ruleIndex+1;
+ }
+ break; // consective space
+ case tColon:
+ case tSemiColon:
+ if ( *ruleIndex != curIndex ) {
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ *ruleIndex=curIndex;
+ type=prevType;
+ getKeyType(token, type, status);
+ return;
+ }
+ else {
+ *ruleIndex=curIndex+1;
+ return;
+ }
+ case tLetter:
+ if ((type==prevType)||(prevType==none)) {
+ prevType=type;
+ break;
+ }
+ break;
+ case tNumber:
+ if ((type==prevType)||(prevType==none)) {
+ prevType=type;
+ break;
+ }
+ else {
+ *ruleIndex=curIndex+1;
+ return;
+ }
+ case tDot:
+ if (prevType==none) { // first dot
+ prevType=type;
+ continue;
+ }
+ else {
+ if ( *ruleIndex != curIndex ) {
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ *ruleIndex=curIndex; // letter
+ type=prevType;
+ getKeyType(token, type, status);
+ return;
+ }
+ else { // two consective dots
+ *ruleIndex=curIndex+2;
+ return;
+ }
+ }
+ break;
+ default:
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ curIndex++;
+ }
+ if ( curIndex>=ruleData.length() ) {
+ if ( (type == tLetter)||(type == tNumber) ) {
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ getKeyType(token, type, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ *ruleIndex = ruleData.length();
+ }
+}
+
+UBool
+RuleParser::inRange(UChar ch, tokenType& type) {
+ if ((ch>=CAP_A) && (ch<=CAP_Z)) {
+ // we assume all characters are in lower case already.
+ return FALSE;
+ }
+ if ((ch>=LOW_A) && (ch<=LOW_Z)) {
+ type = tLetter;
+ return TRUE;
+ }
+ if ((ch>=U_ZERO) && (ch<=U_NINE)) {
+ type = tNumber;
+ return TRUE;
+ }
+ switch (ch) {
+ case COLON:
+ type = tColon;
+ return TRUE;
+ case SPACE:
+ type = tSpace;
+ return TRUE;
+ case SEMI_COLON:
+ type = tSemiColon;
+ return TRUE;
+ case DOT:
+ type = tDot;
+ return TRUE;
+ default :
+ type = none;
+ return FALSE;
+ }
+}
+
+
+void
+RuleParser::getKeyType(const UnicodeString& token, tokenType& keyType, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if ( keyType==tNumber) {
+ }
+ else if (token==PK_VAR_N) {
+ keyType = tVariableN;
+ }
+ else if (token==PK_IS) {
+ keyType = tIs;
+ }
+ else if (token==PK_AND) {
+ keyType = tAnd;
+ }
+ else if (token==PK_IN) {
+ keyType = tIn;
+ }
+ else if (token==PK_WITHIN) {
+ keyType = tWithin;
+ }
+ else if (token==PK_NOT) {
+ keyType = tNot;
+ }
+ else if (token==PK_MOD) {
+ keyType = tMod;
+ }
+ else if (token==PK_OR) {
+ keyType = tOr;
+ }
+ else if ( isValidKeyword(token) ) {
+ keyType = tKeyword;
+ }
+ else {
+ status = U_UNEXPECTED_TOKEN;
+ }
+}
+
+UBool
+RuleParser::isValidKeyword(const UnicodeString& token) {
+ return PatternProps::isIdentifier(token.getBuffer(), token.length());
+}
+
+PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode& status)
+ : pos(0), fKeywordNames(status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fKeywordNames.setDeleter(uhash_deleteUObject);
+ UBool addKeywordOther=TRUE;
+ RuleChain *node=header;
+ while(node!=NULL) {
+ fKeywordNames.addElement(new UnicodeString(node->keyword), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (node->keyword == PLURAL_KEYWORD_OTHER) {
+ addKeywordOther= FALSE;
+ }
+ node=node->next;
+ }
+
+ if (addKeywordOther) {
+ fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status);
+ }
+}
+
+const UnicodeString*
+PluralKeywordEnumeration::snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
+ return (const UnicodeString*)fKeywordNames.elementAt(pos++);
+ }
+ return NULL;
+}
+
+void
+PluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
+ pos=0;
+}
+
+int32_t
+PluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
+ return fKeywordNames.size();
+}
+
+PluralKeywordEnumeration::~PluralKeywordEnumeration() {
+}
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/plurrule_impl.h b/Build/source/libs/icu/icu-4.8.1/i18n/plurrule_impl.h
new file mode 100644
index 00000000000..351b2256cb7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/plurrule_impl.h
@@ -0,0 +1,216 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURRULE_IMPL.H
+*
+*******************************************************************************
+*/
+
+
+#ifndef PLURRULE_IMPLE
+#define PLURRULE_IMPLE
+
+// Internal definitions for the PluralRules implementation.
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/locid.h"
+#include "unicode/parseerr.h"
+#include "unicode/utypes.h"
+#include "uvector.h"
+#include "hash.h"
+
+U_NAMESPACE_BEGIN
+
+#define DOT ((UChar)0x002E)
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define SLASH ((UChar)0x002F)
+#define BACKSLASH ((UChar)0x005C)
+#define SPACE ((UChar)0x0020)
+#define QUOTATION_MARK ((UChar)0x0022)
+#define NUMBER_SIGN ((UChar)0x0023)
+#define ASTERISK ((UChar)0x002A)
+#define COMMA ((UChar)0x002C)
+#define HYPHEN ((UChar)0x002D)
+#define U_ZERO ((UChar)0x0030)
+#define U_ONE ((UChar)0x0031)
+#define U_TWO ((UChar)0x0032)
+#define U_THREE ((UChar)0x0033)
+#define U_FOUR ((UChar)0x0034)
+#define U_FIVE ((UChar)0x0035)
+#define U_SIX ((UChar)0x0036)
+#define U_SEVEN ((UChar)0x0037)
+#define U_EIGHT ((UChar)0x0038)
+#define U_NINE ((UChar)0x0039)
+#define COLON ((UChar)0x003A)
+#define SEMI_COLON ((UChar)0x003B)
+#define CAP_A ((UChar)0x0041)
+#define CAP_B ((UChar)0x0042)
+#define CAP_R ((UChar)0x0052)
+#define CAP_Z ((UChar)0x005A)
+#define LOWLINE ((UChar)0x005F)
+#define LEFTBRACE ((UChar)0x007B)
+#define RIGHTBRACE ((UChar)0x007D)
+
+#define LOW_A ((UChar)0x0061)
+#define LOW_B ((UChar)0x0062)
+#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_J ((UChar)0x006a)
+#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 PLURAL_RANGE_HIGH 0x7fffffff;
+
+
+typedef enum PluralKey {
+ pZero,
+ pOne,
+ pTwo,
+ pFew,
+ pMany,
+ pOther,
+ pLast
+}PluralKey;
+
+typedef enum tokenType {
+ none,
+ tLetter,
+ tNumber,
+ tComma,
+ tSemiColon,
+ tSpace,
+ tColon,
+ tDot,
+ tKeyword,
+ tZero,
+ tOne,
+ tTwo,
+ tFew,
+ tMany,
+ tOther,
+ tAnd,
+ tOr,
+ tMod,
+ tNot,
+ tIn,
+ tWithin,
+ tNotIn,
+ tVariableN,
+ tIs,
+ tLeftBrace,
+ tRightBrace
+}tokenType;
+
+class RuleParser : public UMemory {
+public:
+ RuleParser();
+ virtual ~RuleParser();
+ void getNextToken(const UnicodeString& ruleData, int32_t *ruleIndex, UnicodeString& token,
+ tokenType& type, UErrorCode &status);
+ void checkSyntax(tokenType prevType, tokenType curType, UErrorCode &status);
+private:
+ void getKeyType(const UnicodeString& token, tokenType& type, UErrorCode &status);
+ UBool inRange(UChar ch, tokenType& type);
+ UBool isValidKeyword(const UnicodeString& token);
+};
+
+class AndConstraint : public UMemory {
+public:
+ typedef enum RuleOp {
+ NONE,
+ MOD
+ } RuleOp;
+ RuleOp op;
+ int32_t opNum;
+ int32_t rangeLow;
+ int32_t rangeHigh;
+ UBool notIn;
+ UBool integerOnly;
+ AndConstraint *next;
+
+ AndConstraint();
+ AndConstraint(const AndConstraint& other);
+ virtual ~AndConstraint();
+ AndConstraint* add();
+ UBool isFulfilled(double number);
+ UBool isLimited();
+ int32_t updateRepeatLimit(int32_t maxLimit);
+};
+
+class OrConstraint : public UMemory {
+public:
+ AndConstraint *childNode;
+ OrConstraint *next;
+ OrConstraint();
+
+ OrConstraint(const OrConstraint& other);
+ virtual ~OrConstraint();
+ AndConstraint* add();
+ UBool isFulfilled(double number);
+ UBool isLimited();
+};
+
+class RuleChain : public UMemory {
+public:
+ OrConstraint *ruleHeader;
+ UnicodeString keyword;
+ RuleChain();
+ RuleChain(const RuleChain& other);
+ RuleChain *next;
+
+ virtual ~RuleChain();
+ UnicodeString select(double number) const;
+ void dumpRules(UnicodeString& result);
+ int32_t getRepeatLimit();
+ UBool isLimited();
+ UErrorCode getKeywords(int32_t maxArraySize, UnicodeString *keywords, int32_t& arraySize) const;
+ UBool isKeyword(const UnicodeString& keyword) const;
+ void setRepeatLimit();
+private:
+ int32_t repeatLimit;
+};
+
+class PluralKeywordEnumeration : public StringEnumeration {
+public:
+ PluralKeywordEnumeration(RuleChain *header, UErrorCode& status);
+ virtual ~PluralKeywordEnumeration();
+ 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;
+ UVector fKeywordNames;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _PLURRULE_IMPL
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/quant.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/quant.cpp
new file mode 100644
index 00000000000..3b48290867f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/quant.cpp
@@ -0,0 +1,146 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2008, 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-4.8.1/i18n/quant.h b/Build/source/libs/icu/icu-4.8.1/i18n/quant.h
new file mode 100644
index 00000000000..f84c4313325
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/quant.h
@@ -0,0 +1,124 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2001-2011, 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.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ 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-4.8.1/i18n/rbnf.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbnf.cpp
new file mode 100644
index 00000000000..edd8bc9ebef
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbnf.cpp
@@ -0,0 +1,1623 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, International Business Machines Corporation
+* and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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 "patternprops.h"
+#include "uresimp.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)
+
+// Temporary workaround - when noParse is true, do noting in parse.
+// TODO: We need a real fix - see #6895/#6896
+static const char *NO_SPELLOUT_PARSE_LANGUAGES[] = { "ga", NULL };
+
+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 && PatternProps::isWhiteSpace(ch != 0xffff ? ch : *p)) inc();}
+ UBool inList(UChar c, const UChar* list) const {
+ if (*list == SPACE && PatternProps::isWhiteSpace(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)
+ , noParse(FALSE) //TODO: to be removed after #6895
+{
+ 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)
+ , noParse(FALSE) //TODO: to be removed after #6895
+{
+ 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)
+ , noParse(FALSE) //TODO: to be removed after #6895
+{
+ 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)
+ , noParse(FALSE) //TODO: to be removed after #6895
+{
+ 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)
+ , noParse(FALSE) //TODO: to be removed after #6895
+{
+ 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* rules_tag = "RBNFRules";
+ 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;
+ case URBNF_NUMBERING_SYSTEM: fmt_tag = "NumberingSystemRules"; 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));
+
+ UResourceBundle* rbnfRules = ures_getByKeyWithFallback(nfrb, rules_tag, NULL, &status);
+ if (U_FAILURE(status)) {
+ ures_close(nfrb);
+ }
+ UResourceBundle* ruleSets = ures_getByKeyWithFallback(rbnfRules, fmt_tag, NULL, &status);
+ if (U_FAILURE(status)) {
+ ures_close(rbnfRules);
+ ures_close(nfrb);
+ return;
+ }
+
+ UnicodeString desc;
+ while (ures_hasNext(ruleSets)) {
+ const UChar* currentString = ures_getNextString(ruleSets,&len,NULL,&status);
+ desc.append(currentString);
+ }
+ UParseError perror;
+
+
+ init (desc, locinfo, perror, status);
+
+ //TODO: we need a real fix - see #6895 / #6896
+ noParse = FALSE;
+ if (tag == URBNF_SPELLOUT) {
+ const char *lang = alocale.getLanguage();
+ for (int32_t i = 0; NO_SPELLOUT_PARSE_LANGUAGES[i] != NULL; i++) {
+ if (uprv_strcmp(lang, NO_SPELLOUT_PARSE_LANGUAGES[i]) == 0) {
+ noParse = TRUE;
+ break;
+ }
+ }
+ }
+ //TODO: end
+
+ ures_close(ruleSets);
+ ures_close(rbnfRules);
+ }
+ 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);
+
+ //TODO: remove below when we fix the parse bug - See #6895 / #6896
+ noParse = rhs.noParse;
+
+ 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;
+
+ //TODO: remove below when we fix the parse bug - See #6895 / #6896
+ result->noParse = noParse;
+ }
+ return result;
+}
+
+UBool
+RuleBasedNumberFormat::operator==(const Format& other) const
+{
+ if (this == &other) {
+ return TRUE;
+ }
+
+ if (typeid(*this) == typeid(other)) {
+ 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
+{
+ // Special case for NaN; adapted from what DecimalFormat::_format( double number,...) does.
+ if (uprv_isNaN(number)) {
+ DecimalFormatSymbols* decFmtSyms = getDecimalFormatSymbols(); // RuleBasedNumberFormat internal
+ if (decFmtSyms) {
+ toAppendTo += decFmtSyms->getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+ }
+ } else 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
+{
+ //TODO: We need a real fix. See #6895 / #6896
+ if (noParse) {
+ // skip parsing
+ parsePosition.setErrorIndex(0);
+ return;
+ }
+
+ 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() && rp->isParseable()) {
+ 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;
+ }
+ }
+ }
+ }
+
+ int32_t startIndex = parsePosition.getIndex();
+ parsePosition.setIndex(startIndex + high_pp.getIndex());
+ if (high_pp.getIndex() > 0) {
+ parsePosition.setErrorIndex(-1);
+ } else {
+ int32_t errorIndex = (high_pp.getErrorIndex()>0)? high_pp.getErrorIndex(): 0;
+ parsePosition.setErrorIndex(startIndex + errorIndex);
+ }
+ 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;
+ }
+
+ const UnicodeString spellout = UNICODE_STRING_SIMPLE("%spellout-numbering");
+ const UnicodeString ordinal = UNICODE_STRING_SIMPLE("%digits-ordinal");
+ const UnicodeString duration = UNICODE_STRING_SIMPLE("%duration");
+
+ NFRuleSet**p = &ruleSets[0];
+ while (*p) {
+ if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) {
+ defaultRuleSet = *p;
+ return;
+ } else {
+ ++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 (PatternProps::isWhiteSpace(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];
+ 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);
+ if (ruleSets[curRuleSet] == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ ++curRuleSet;
+ start = p + 1;
+ }
+ ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start);
+ ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet, status);
+ if (ruleSets[curRuleSet] == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ }
+
+ // 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);
+ }
+ }
+
+ // 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();
+ }
+
+cleanup:
+ delete[] ruleSetDescriptions;
+}
+
+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()
+ && PatternProps::isWhiteSpace(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);
+ RuleBasedCollator* newCollator;
+ if (U_SUCCESS(status) && (newCollator = dynamic_cast<RuleBasedCollator*>(temp)) != NULL) {
+ if (lenientParseRules) {
+ UnicodeString rules(newCollator->getRules());
+ rules.append(*lenientParseRules);
+
+ newCollator = new RuleBasedCollator(rules, status);
+ // Exit if newCollator could not be created.
+ if (newCollator == NULL) {
+ return NULL;
+ }
+ } 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-4.8.1/i18n/rbt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbt.cpp
new file mode 100644
index 00000000000..6041a9245e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbt.cpp
@@ -0,0 +1,295 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2008, 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;
+ }
+ }
+
+ // Check to make sure we don't dereference a null pointer.
+ if (fData != NULL) {
+ 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-4.8.1/i18n/rbt.h b/Build/source/libs/icu/icu-4.8.1/i18n/rbt.h
new file mode 100644
index 00000000000..d061de6e637
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/rbt_data.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_data.cpp
new file mode 100644
index 00000000000..beef99231f9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_data.cpp
@@ -0,0 +1,117 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2008, 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;
+ int32_t i = 0;
+ 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);
+ // Exit out if value could not be created.
+ if (value == NULL) {
+ return;
+ }
+ 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 (i=0; i<variablesLength; ++i) {
+ variables[i] = other.variables[i]->clone();
+ if (variables[i] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ }
+ }
+ // Remove the array and exit if memory allocation error occured.
+ if (U_FAILURE(status)) {
+ for (int32_t n = i-1; n >= 0; n++) {
+ delete variables[n];
+ }
+ uprv_free(variables);
+ variables = NULL;
+ return;
+ }
+
+ // 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-4.8.1/i18n/rbt_data.h b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_data.h
new file mode 100644
index 00000000000..ce833dc26dd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/rbt_pars.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_pars.cpp
new file mode 100644
index 00000000000..d05a0cc925b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_pars.cpp
@@ -0,0 +1,1733 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2011, 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 "patternprops.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 (PatternProps::isWhiteSpace(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);
+ if (m == NULL) {
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+
+ // 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));
+ if (r == NULL) {
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+
+ // 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);
+ if (m == NULL) {
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+ 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);
+ if (m == NULL) {
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+ 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 *tempstr = NULL; // used for memory allocation error checking
+ 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 (PatternProps::isWhiteSpace(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 (PatternProps::isWhiteSpace(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) {
+ tempstr = new UnicodeString(idBlockResult);
+ // NULL pointer check
+ if (tempstr == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (direction == UTRANS_FORWARD)
+ idBlockVector.addElement(tempstr, status);
+ else
+ idBlockVector.insertElementAt(tempstr, 0, status);
+ idBlockResult.remove();
+ parsingIDs = FALSE;
+ curData = new TransliterationRuleData(status);
+ // NULL pointer check
+ if (curData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ 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) {
+ tempstr = new UnicodeString(idBlockResult);
+ // NULL pointer check
+ if (tempstr == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (direction == UTRANS_FORWARD)
+ idBlockVector.addElement(tempstr, status);
+ else
+ idBlockVector.insertElementAt(tempstr, 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*));
+ // NULL pointer check
+ if (data->variables == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ 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) {
+ UnicodeString* tempus = (UnicodeString*)(((UnicodeString*)(he->value.pointer))->clone());
+ if (tempus == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ data->variableNames.put(*((UnicodeString*)(he->key.pointer)),
+ tempus, 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);
+ // NULL pointer check
+ if (value == NULL) {
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+ 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 *));
+ // Null pointer check
+ if (segmentsArray == NULL) {
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+ segmentObjects.toArray((void**) segmentsArray);
+ }
+ TransliterationRule* temptr = new TransliterationRule(
+ left->text, left->ante, left->post,
+ right->text, right->cursor, right->cursorOffset,
+ segmentsArray,
+ segmentObjects.size(),
+ left->anchorStart, left->anchorEnd,
+ curData,
+ status);
+ //Null pointer check
+ if (temptr == NULL) {
+ uprv_free(segmentsArray);
+ return syntaxError(U_MEMORY_ALLOCATION_ERROR, rule, start, status);
+ }
+
+ curData->ruleSet.addRule(temptr, 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);
+ // Null pointer check
+ if (set == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return (UChar)0x0000; // Return empty character with error.
+ }
+ 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, status);
+ }
+ 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) {
+ UnicodeSet* tempus = new UnicodeSet(DOT_SET, status);
+ // Null pointer check.
+ if (tempus == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return (UChar)0x0000;
+ }
+ dotStandIn = generateStandInFor(tempus, 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 (!PatternProps::isWhiteSpace(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-4.8.1/i18n/rbt_pars.h b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_pars.h
new file mode 100644
index 00000000000..96bdac06479
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/rbt_rule.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_rule.cpp
new file mode 100644
index 00000000000..69a22026374
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_rule.cpp
@@ -0,0 +1,556 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2008, 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-4.8.1/i18n/rbt_rule.h b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_rule.h
new file mode 100644
index 00000000000..0816956ce81
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/rbt_set.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_set.cpp
new file mode 100644
index 00000000000..1553c4f0419
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_set.cpp
@@ -0,0 +1,466 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2008, 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);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (ruleVector == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ rules = NULL;
+ maxContextLength = 0;
+}
+
+/**
+ * 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) {
+ TransliterationRule *tempTranslitRule = new TransliterationRule(*(TransliterationRule*)other.ruleVector->elementAt(i));
+ // Null pointer test
+ if (tempTranslitRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ ruleVector->addElement(tempTranslitRule, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+ }
+ if (other.rules != 0 && U_SUCCESS(status)) {
+ 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-4.8.1/i18n/rbt_set.h b/Build/source/libs/icu/icu-4.8.1/i18n/rbt_set.h
new file mode 100644
index 00000000000..f92e13002c2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/rbtz.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rbtz.cpp
new file mode 100644
index 00000000000..961c8fb2de4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rbtz.cpp
@@ -0,0 +1,934 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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 (typeid(*this) != typeid(that)
+ || 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;
+ }
+ AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule);
+ if (atzrule != NULL && atzrule->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) {
+ uprv_free(final0);
+ 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 (typeid(*this) != typeid(other)) {
+ 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-4.8.1/i18n/regexcmp.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.cpp
new file mode 100644
index 00000000000..968d08123fd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.cpp
@@ -0,0 +1,4324 @@
+//
+// file: regexcmp.cpp
+//
+// Copyright (C) 2002-2011 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/ustring.h"
+#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 "patternprops.h"
+#include "putilimp.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uvectr32.h"
+#include "uvectr64.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uinvchar.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"
+#include "regextxt.h"
+
+
+
+U_NAMESPACE_BEGIN
+
+
+//------------------------------------------------------------------------------
+//
+// Constructor.
+//
+//------------------------------------------------------------------------------
+RegexCompile::RegexCompile(RegexPattern *rxp, UErrorCode &status) :
+ fParenStack(status), fSetStack(status), fSetOpStack(status)
+{
+ // Lazy init of all shared global sets (needed for init()'s empty text)
+ RegexStaticSets::initGlobals(&status);
+
+ fStatus = &status;
+
+ fRXPat = rxp;
+ fScanIndex = 0;
+ fLastChar = -1;
+ 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;
+ }
+}
+
+static const UChar chAmp = 0x26; // '&'
+static const UChar chDash = 0x2d; // '-'
+
+
+//------------------------------------------------------------------------------
+//
+// Destructor
+//
+//------------------------------------------------------------------------------
+RegexCompile::~RegexCompile() {
+}
+
+static inline void addCategory(UnicodeSet *set, int32_t value, UErrorCode& ec) {
+ set->addAll(UnicodeSet().applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, value, ec));
+}
+
+//------------------------------------------------------------------------------
+//
+// 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
+{
+ fRXPat->fPatternString = new UnicodeString(pat);
+ UText patternText = UTEXT_INITIALIZER;
+ utext_openConstUnicodeString(&patternText, fRXPat->fPatternString, &e);
+
+ if (U_SUCCESS(e)) {
+ compile(&patternText, pp, e);
+ utext_close(&patternText);
+ }
+}
+
+//
+// compile, UText mode
+// All the work is actually done here.
+//
+void RegexCompile::compile(
+ UText *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 == NULL || utext_nativeLength(fRXPat->fPattern) == 0);
+
+ // Prepare the RegexPattern object to receive the compiled pattern.
+ fRXPat->fPattern = utext_clone(fRXPat->fPattern, pat, FALSE, TRUE, fStatus);
+ fRXPat->fStaticSets = RegexStaticSets::gStaticSets->fPropSets;
+ fRXPat->fStaticSets8 = RegexStaticSets::gStaticSets->fPropSets8;
+
+
+ // Initialize the pattern scanning state machine
+ fPatternLength = utext_nativeLength(pat);
+ 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
+ if (RegexStaticSets::gStaticSets->fRuleSets[tableEl->fCharClass-128].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);
+ }
+ }
+
+ }
+
+ if (U_FAILURE(*fStatus)) {
+ // Bail out if the pattern had errors.
+ // Set stack cleanup: a successful compile would have left it empty,
+ // but errors can leave temporary sets hanging around.
+ while (!fSetStack.empty()) {
+ delete (UnicodeSet *)fSetStack.pop();
+ }
+ return;
+ }
+
+ //
+ // The pattern has now been read and processed, and the compiled code generated.
+ //
+
+ //
+ // Compute the number of digits requried for the largest capture group number.
+ //
+ fRXPat->fMaxCaptureDigits = 1;
+ int32_t n = 10;
+ int32_t groupCount = fRXPat->fGroupMap->size();
+ while (n <= groupCount) {
+ 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 (int64_t) and
+ // the position in the compiled pattern.
+ //
+ fRXPat->fFrameSize+=RESTACKFRAME_HDRCOUNT;
+
+ //
+ // Optimization pass 1: NOPs, back-references, and case-folding
+ //
+ stripNOPs();
+
+ //
+ // 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 pass 2: match start type
+ //
+ matchStartType();
+
+ //
+ // Set up fast latin-1 range sets
+ //
+ int32_t numSets = fRXPat->fSets->size();
+ fRXPat->fSets8 = new Regex8BitSet[numSets];
+ // Null pointer check.
+ if (fRXPat->fSets8 == NULL) {
+ e = *fStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ 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 = (int32_t)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 position.
+ // 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_CAPTURE 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 )
+ //
+ // Note: Addition of transparent input regions, with the need to
+ // restore the original regions when failing out of a lookahead
+ // block, complicated this sequence. Some conbined opcodes
+ // might make sense - or might not, lookahead aren't that common.
+ //
+ // Caution: min match length optimization knows about this
+ // sequence; don't change without making updates there too.
+ //
+ // Compiles to
+ // 1 START_LA dataLoc Saves SP, Input Pos
+ // 2. STATE_SAVE 4 on failure of lookahead, goto 4
+ // 3 JMP 6 continue ...
+ //
+ // 4. LA_END Look Ahead failed. Restore regions.
+ // 5. BACKTRACK and back track again.
+ //
+ // 6. 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.
+ // 7. NOP may be replaced if there is are '|' ops in the block.
+ // 8. code for parenthesized stuff.
+ // 9. LA_END
+ //
+ // 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_STATE_SAVE, fRXPat->fCompiledPat->size()+ 2);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ op = URX_BUILD(URX_JMP, fRXPat->fCompiledPat->size()+ 3);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ op = URX_BUILD(URX_LA_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ op = URX_BUILD(URX_BACKTRACK, 0);
+ 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. BACKTRACK // code in block succeeded, so neg. lookahead fails.
+ // 7. END_LA // Restore match region, in case look-ahead was using
+ // an alternate (transparent) region.
+ {
+ 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 - #7 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 = (int32_t)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 ||
+ URX_TYPE(repeatedOp) == URX_DOTANY_UNIX) {
+ // 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;
+ }
+ if (fModeFlags & UREGEX_UNIX_LINES) {
+ loopOpI |= 2;
+ }
+ 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 = (int32_t)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 ||
+ URX_TYPE(repeatedOp) == URX_DOTANY_UNIX) {
+ // 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;
+ }
+ if ((fModeFlags & UREGEX_UNIX_LINES) != 0) {
+ loopOpI |= 2;
+ }
+ 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, because
+ // 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 = (int32_t)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 doEscapedLiteralChar:
+ // We've just scanned an backslashed escaped character with no
+ // special meaning. It represents itself.
+ if ((fModeFlags & UREGEX_ERROR_ON_UNKNOWN_ESCAPES) != 0 &&
+ ((fC.fChar >= 0x41 && fC.fChar<= 0x5A) || // in [A-Z]
+ (fC.fChar >= 0x61 && fC.fChar <= 0x7a))) { // in [a-z]
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ }
+ 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 if (fModeFlags & UREGEX_UNIX_LINES) {
+ op = URX_BUILD(URX_DOTANY_UNIX, 0);
+ } else {
+ op = URX_BUILD(URX_DOTANY, 0);
+ }
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+ case doCaret:
+ {
+ int32_t op = 0;
+ if ( (fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
+ op = URX_CARET;
+ } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
+ op = URX_CARET_M;
+ } else if ((fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
+ op = URX_CARET; // Only testing true start of input.
+ } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
+ op = URX_CARET_M_UNIX;
+ }
+ fRXPat->fCompiledPat->addElement(URX_BUILD(op, 0), *fStatus);
+ }
+ break;
+
+ case doDollar:
+ {
+ int32_t op = 0;
+ if ( (fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
+ op = URX_DOLLAR;
+ } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
+ op = URX_DOLLAR_M;
+ } else if ((fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
+ op = URX_DOLLAR_D;
+ } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
+ op = URX_DOLLAR_MD;
+ }
+ 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 doNamedChar:
+ {
+ UChar32 c = scanNamedChar();
+ literalChar(c);
+ }
+ 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. Ticket 6056
+ //
+ {
+ // 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 0x64: /* 'd' */ bit = UREGEX_UNIX_LINES; break;
+ case 0x6d: /* 'm' */ bit = UREGEX_MULTILINE; break;
+ case 0x73: /* 's' */ bit = UREGEX_DOTALL; break;
+ case 0x75: /* 'u' */ bit = 0; /* Unicode casing */ 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;
+
+
+ case doSetAddAmp:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ set->add(chAmp);
+ }
+ break;
+
+ case doSetAddDash:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ set->add(chDash);
+ }
+ break;
+
+ case doSetBackslash_s:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ set->addAll(*RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]);
+ break;
+ }
+
+ case doSetBackslash_S:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ UnicodeSet SSet(*RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]);
+ SSet.complement();
+ set->addAll(SSet);
+ break;
+ }
+
+ case doSetBackslash_d:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ // TODO - make a static set, ticket 6058.
+ addCategory(set, U_GC_ND_MASK, *fStatus);
+ break;
+ }
+
+ case doSetBackslash_D:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ UnicodeSet digits;
+ // TODO - make a static set, ticket 6058.
+ digits.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ND_MASK, *fStatus);
+ digits.complement();
+ set->addAll(digits);
+ break;
+ }
+
+ case doSetBackslash_w:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ set->addAll(*RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]);
+ break;
+ }
+
+ case doSetBackslash_W:
+ {
+ UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
+ UnicodeSet SSet(*RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]);
+ SSet.complement();
+ set->addAll(SSet);
+ break;
+ }
+
+ case doSetBegin:
+ fSetStack.push(new UnicodeSet(), *fStatus);
+ fSetOpStack.push(setStart, *fStatus);
+ if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
+ fSetOpStack.push(setCaseClose, *fStatus);
+ }
+ break;
+
+ case doSetBeginDifference1:
+ // We have scanned something like [[abc]-[
+ // Set up a new UnicodeSet for the set beginning with the just-scanned '['
+ // Push a Difference operator, which will cause the new set to be subtracted from what
+ // went before once it is created.
+ setPushOp(setDifference1);
+ fSetOpStack.push(setStart, *fStatus);
+ if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
+ fSetOpStack.push(setCaseClose, *fStatus);
+ }
+ break;
+
+ case doSetBeginIntersection1:
+ // We have scanned something like [[abc]&[
+ // Need both the '&' operator and the open '[' operator.
+ setPushOp(setIntersection1);
+ fSetOpStack.push(setStart, *fStatus);
+ if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
+ fSetOpStack.push(setCaseClose, *fStatus);
+ }
+ break;
+
+ case doSetBeginUnion:
+ // We have scanned something like [[abc][
+ // Need to handle the union operation explicitly [[abc] | [
+ setPushOp(setUnion);
+ fSetOpStack.push(setStart, *fStatus);
+ if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
+ fSetOpStack.push(setCaseClose, *fStatus);
+ }
+ break;
+
+ case doSetDifference2:
+ // We have scanned something like [abc--
+ // Consider this to unambiguously be a set difference operator.
+ setPushOp(setDifference2);
+ break;
+
+ case doSetEnd:
+ // Have encountered the ']' that closes a set.
+ // Force the evaluation of any pending operations within this set,
+ // leave the completed set on the top of the set stack.
+ setEval(setEnd);
+ U_ASSERT(fSetOpStack.peeki()==setStart);
+ fSetOpStack.popi();
+ break;
+
+ case doSetFinish:
+ {
+ // Finished a complete set expression, including all nested sets.
+ // The close bracket has already triggered clearing out pending set operators,
+ // the operator stack should be empty and the operand stack should have just
+ // one entry, the result set.
+ U_ASSERT(fSetOpStack.empty());
+ UnicodeSet *theSet = (UnicodeSet *)fSetStack.pop();
+ U_ASSERT(fSetStack.empty());
+ compileSet(theSet);
+ break;
+ }
+
+ case doSetIntersection2:
+ // Have scanned something like [abc&&
+ setPushOp(setIntersection2);
+ break;
+
+ case doSetLiteral:
+ // Union the just-scanned literal character into the set being built.
+ // This operation is the highest precedence set operation, so we can always do
+ // it immediately, without waiting to see what follows. It is necessary to perform
+ // any pending '-' or '&' operation first, because these have the same precedence
+ // as union-ing in a literal'
+ {
+ setEval(setUnion);
+ UnicodeSet *s = (UnicodeSet *)fSetStack.peek();
+ s->add(fC.fChar);
+ fLastSetLiteral = fC.fChar;
+ break;
+ }
+
+ case doSetLiteralEscaped:
+ // A back-slash escaped literal character was encountered.
+ // Processing is the same as with setLiteral, above, with the addition of
+ // the optional check for errors on escaped ASCII letters.
+ {
+ if ((fModeFlags & UREGEX_ERROR_ON_UNKNOWN_ESCAPES) != 0 &&
+ ((fC.fChar >= 0x41 && fC.fChar<= 0x5A) || // in [A-Z]
+ (fC.fChar >= 0x61 && fC.fChar <= 0x7a))) { // in [a-z]
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ }
+ setEval(setUnion);
+ UnicodeSet *s = (UnicodeSet *)fSetStack.peek();
+ s->add(fC.fChar);
+ fLastSetLiteral = fC.fChar;
+ break;
+ }
+
+ case doSetNamedChar:
+ // Scanning a \N{UNICODE CHARACTER NAME}
+ // Aside from the source of the character, the processing is identical to doSetLiteral,
+ // above.
+ {
+ UChar32 c = scanNamedChar();
+ setEval(setUnion);
+ UnicodeSet *s = (UnicodeSet *)fSetStack.peek();
+ s->add(c);
+ fLastSetLiteral = c;
+ break;
+ }
+
+ case doSetNamedRange:
+ // We have scanned literal-\N{CHAR NAME}. Add the range to the set.
+ // The left character is already in the set, and is saved in fLastSetLiteral.
+ // The right side needs to be picked up, the scan is at the 'N'.
+ // Lower Limit > Upper limit being an error matches both Java
+ // and ICU UnicodeSet behavior.
+ {
+ UChar32 c = scanNamedChar();
+ if (U_SUCCESS(*fStatus) && fLastSetLiteral > c) {
+ error(U_REGEX_INVALID_RANGE);
+ }
+ UnicodeSet *s = (UnicodeSet *)fSetStack.peek();
+ s->add(fLastSetLiteral, c);
+ fLastSetLiteral = c;
+ break;
+ }
+
+
+ case doSetNegate:
+ // Scanned a '^' at the start of a set.
+ // Push the negation operator onto the set op stack.
+ // A twist for case-insensitive matching:
+ // the case closure operation must happen _before_ negation.
+ // But the case closure operation will already be on the stack if it's required.
+ // This requires checking for case closure, and swapping the stack order
+ // if it is present.
+ {
+ int32_t tosOp = fSetOpStack.peeki();
+ if (tosOp == setCaseClose) {
+ fSetOpStack.popi();
+ fSetOpStack.push(setNegation, *fStatus);
+ fSetOpStack.push(setCaseClose, *fStatus);
+ } else {
+ fSetOpStack.push(setNegation, *fStatus);
+ }
+ }
+ break;
+
+ case doSetNoCloseError:
+ error(U_REGEX_MISSING_CLOSE_BRACKET);
+ break;
+
+ case doSetOpError:
+ error(U_REGEX_RULE_SYNTAX); // -- or && at the end of a set. Illegal.
+ break;
+
+ case doSetPosixProp:
+ {
+ UnicodeSet *s = scanPosixProp();
+ if (s != NULL) {
+ UnicodeSet *tos = (UnicodeSet *)fSetStack.peek();
+ tos->addAll(*s);
+ delete s;
+ } // else error. scanProp() reported the error status already.
+ }
+ break;
+
+ case doSetProp:
+ // Scanned a \p \P within [brackets].
+ {
+ UnicodeSet *s = scanProp();
+ if (s != NULL) {
+ UnicodeSet *tos = (UnicodeSet *)fSetStack.peek();
+ tos->addAll(*s);
+ delete s;
+ } // else error. scanProp() reported the error status already.
+ }
+ break;
+
+
+ case doSetRange:
+ // We have scanned literal-literal. Add the range to the set.
+ // The left character is already in the set, and is saved in fLastSetLiteral.
+ // The right side is the current character.
+ // Lower Limit > Upper limit being an error matches both Java
+ // and ICU UnicodeSet behavior.
+ {
+ if (fLastSetLiteral > fC.fChar) {
+ error(U_REGEX_INVALID_RANGE);
+ }
+ UnicodeSet *s = (UnicodeSet *)fSetStack.peek();
+ s->add(fLastSetLiteral, fC.fChar);
+ 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 = (int32_t)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);
+
+ // Mark that we might actually be starting a string here
+ fStringOpStart = fRXPat->fLiteralText.length();
+ return;
+ }
+
+ op = (int32_t)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.
+ fRXPat->fLiteralText.append(URX_VAL(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);
+ }
+
+ // We are adding onto an existing string
+ fRXPat->fLiteralText.append(c);
+
+ // 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); // !!!: handled in stripNOPs() now
+ 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 = (int32_t)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) {
+ UVector64 *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 = (int32_t)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_JMP_SAV_X ||
+ 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 = (int32_t)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 = (int32_t)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 = (int32_t)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 = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
+ 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 = (int32_t)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_BACKTRACK, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ op = URX_BUILD(URX_LA_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Patch the URX_SAVE near the top of the block.
+ // The destination of the SAVE is the final LA_END that was just added.
+ int32_t saveOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen);
+ U_ASSERT(URX_TYPE(saveOp) == URX_STATE_SAVE);
+ int32_t dest = fRXPat->fCompiledPat->size()-1;
+ 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 = (int32_t)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 = (int32_t)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;
+ }
+ // Remove any strings from the set.
+ // There shoudn't be any, but just in case.
+ // (Case Closure can add them; if we had a simple case closure avaialble that
+ // ignored strings, that would be better.)
+ theSet->removeAllStrings();
+ int32_t setSize = theSet->size();
+
+ 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(theSet->charAt(0));
+ 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 = (int32_t)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 = (int32_t)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.
+ 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_FAIL:
+ 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_DOLLAR_M:
+ case URX_DOLLAR_D:
+ case URX_DOLLAR_MD:
+ case URX_RELOC_OPRND:
+ case URX_STO_INP_LOC:
+ 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:
+ case URX_CARET_M_UNIX:
+ 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_UNIX:
+ 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_BACKTRACK:
+ // 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 = (int32_t)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 = (int32_t)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 = (int32_t)fRXPat->fCompiledPat->elementAti(loc+1);
+ loopEndLoc = URX_VAL(loopEndLoc);
+ int32_t minLoopCount = (int32_t)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.
+
+ // Keep track of the nesting depth of look-around blocks. Boilerplate code for
+ // lookahead contains two LA_END instructions, so count goes up by two
+ // for each LA_START.
+ int32_t depth = (opType == URX_LA_START? 2: 1);
+ for (;;) {
+ loc++;
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_LA_START) {
+ depth+=2;
+ }
+ if (URX_TYPE(op) == URX_LB_START) {
+ depth++;
+ }
+ if (URX_TYPE(op) == URX_LA_END || URX_TYPE(op)==URX_LBN_END) {
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+ }
+ 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 = (int32_t)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); // MinLength == INT32_MAX for some
+ // no-match-possible cases.
+ 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_DOLLAR_M:
+ case URX_DOLLAR_D:
+ case URX_DOLLAR_MD:
+ case URX_RELOC_OPRND:
+ case URX_STO_INP_LOC:
+ case URX_CARET_M:
+ case URX_CARET_M_UNIX:
+ 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_UNIX:
+ 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_BACKTRACK:
+ {
+ // Back-tracks are kind of like a branch, except that the min 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.
+ 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 = (int32_t)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 = (int32_t)fRXPat->fCompiledPat->elementAti(loc+1);
+ loopEndLoc = URX_VAL(loopEndLoc);
+ int32_t minLoopCount = (int32_t)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 for look-ahead,
+ // it assumes that the look-ahead match might be zero-length.
+ // TODO: Positive lookahead could recursively do the block, then continue
+ // with the longer of the block or the value coming in. Ticket 6060
+ int32_t depth = (opType == URX_LA_START? 2: 1);;
+ for (;;) {
+ loc++;
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_LA_START) {
+ // The boilerplate for look-ahead includes two LA_END insturctions,
+ // Depth will be decremented by each one when it is seen.
+ depth += 2;
+ }
+ if (URX_TYPE(op) == URX_LB_START) {
+ depth++;
+ }
+ if (URX_TYPE(op) == URX_LA_END) {
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+ }
+ if (URX_TYPE(op)==URX_LBN_END) {
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+ }
+ 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 = (int32_t)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_DOLLAR_M:
+ case URX_DOLLAR_D:
+ case URX_DOLLAR_MD:
+ case URX_RELOC_OPRND:
+ case URX_STO_INP_LOC:
+ case URX_CARET_M:
+ case URX_CARET_M_UNIX:
+
+ 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.
+ 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:
+ case URX_DOTANY_UNIX:
+ 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_BACKTRACK:
+ // back-tracks 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 = (int32_t)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 = (int32_t)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.
+//
+// In order to minimize the number of passes through the pattern,
+// back-reference fixup is also performed here (adjusting
+// back-reference operands to point to the correct frame offsets).
+//
+// In addition, case-insensitive character and string literals are
+// now case-folded here, rather than when first parsed or at match
+// time.
+//
+//------------------------------------------------------------------------------
+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 = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_NOP) {
+ d++;
+ }
+ }
+
+ UnicodeString caseStringBuffer;
+ int32_t stringDelta = 0;
+
+ // 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 = (int32_t)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_ONECHAR_I:
+ {
+ UChar32 c = URX_VAL(op);
+ if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
+ // We have a cased character to fold
+ c = u_foldCase(c, U_FOLD_CASE_DEFAULT);
+ op = URX_BUILD(URX_ONECHAR_I, c);
+ }
+
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ dst++;
+ break;
+ }
+ case URX_STRING_I:
+ {
+ op = URX_BUILD(URX_STRING_I, URX_VAL(op)+stringDelta);
+
+ src++;
+ int32_t lengthOp = (int32_t)fRXPat->fCompiledPat->elementAti(src);
+
+ caseStringBuffer.setTo(fRXPat->fLiteralText, URX_VAL(op), URX_VAL(lengthOp));
+ caseStringBuffer.foldCase(U_FOLD_CASE_DEFAULT);
+
+ int32_t newLen = caseStringBuffer.length();
+ if (newLen <= URX_VAL(lengthOp)) {
+ // don't shift if we don't have to, take the tiny memory hit of a smaller string
+ fRXPat->fLiteralText.replace(URX_VAL(op), newLen, caseStringBuffer);
+ } else {
+ // shift other strings over...at least UnicodeString handles this for us!
+ fRXPat->fLiteralText.replace(URX_VAL(op), URX_VAL(lengthOp), caseStringBuffer);
+ stringDelta += newLen - URX_VAL(lengthOp);
+ }
+ lengthOp = URX_BUILD(URX_STRING_LEN, newLen);
+
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ fRXPat->fCompiledPat->setElementAt(lengthOp, dst+1);
+ dst += 2;
+ break;
+ }
+ case URX_BACKREF:
+ case 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, dst);
+ dst++;
+
+ fRXPat->fNeedsAltInput = TRUE;
+ break;
+ }
+ case URX_STRING:
+ op = URX_BUILD(URX_STRING, URX_VAL(op)+stringDelta);
+ // continue
+ case URX_RESERVED_OP:
+ case URX_RESERVED_OP_N:
+ case URX_BACKTRACK:
+ case URX_END:
+ case URX_ONECHAR:
+ 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_BACKSLASH_D:
+ case URX_CARET:
+ case URX_DOLLAR:
+ case URX_CTR_INIT:
+ case URX_CTR_INIT_NG:
+ case URX_DOTANY_UNIX:
+ case URX_STO_SP:
+ case URX_LD_SP:
+ case URX_STO_INP_LOC:
+ case URX_LA_START:
+ case URX_LA_END:
+ case URX_DOLLAR_M:
+ case URX_CARET_M:
+ case URX_CARET_M_UNIX:
+ 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:
+ case URX_DOLLAR_D:
+ case URX_DOLLAR_MD:
+ // 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);
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// 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;
+ // Hmm. fParseErr (UParseError) line & offset fields are int32_t in public
+ // API (see common/unicode/parseerr.h), while fLineNum and fCharNum are
+ // int64_t. If the values of the latter are out of range for the former,
+ // set them to the appropriate "field not supported" values.
+ if (fLineNum > 0x7FFFFFFF) {
+ fParseErr->line = 0;
+ fParseErr->offset = -1;
+ } else if (fCharNum > 0x7FFFFFFF) {
+ fParseErr->line = (int32_t)fLineNum;
+ fParseErr->offset = -1;
+ } else {
+ fParseErr->line = (int32_t)fLineNum;
+ fParseErr->offset = (int32_t)fCharNum;
+ }
+
+ UErrorCode status = U_ZERO_ERROR; // throwaway status for extracting context
+
+ // 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));
+ utext_extract(fRXPat->fPattern, fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex, fParseErr->preContext, U_PARSE_CONTEXT_LEN, &status);
+ utext_extract(fRXPat->fPattern, fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1, fParseErr->postContext, U_PARSE_CONTEXT_LEN, &status);
+ }
+}
+
+
+//
+// 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; // Line Feed
+static const UChar chPound = 0x23; // '#', introduces a comment.
+static const UChar chDigit0 = 0x30; // '0'
+static const UChar chDigit7 = 0x37; // '9'
+static const UChar chColon = 0x3A; // ':'
+static const UChar chE = 0x45; // 'E'
+static const UChar chQ = 0x51; // 'Q'
+static const UChar chN = 0x4E; // 'N'
+static const UChar chP = 0x50; // 'P'
+static const UChar chBackSlash = 0x5c; // '\' introduces a char escape
+static const UChar chLBracket = 0x5b; // '['
+static const UChar chRBracket = 0x5d; // ']'
+static const UChar chUp = 0x5e; // '^'
+static const UChar chLowerP = 0x70;
+static const UChar chLBrace = 0x7b; // '{'
+static const UChar chRBrace = 0x7d; // '}'
+static const UChar chNEL = 0x85; // NEL newline variant
+static const UChar chLS = 0x2028; // Unicode Line Separator
+
+
+//------------------------------------------------------------------------------
+//
+// 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;
+
+ if (fPeekChar != -1) {
+ ch = fPeekChar;
+ fPeekChar = -1;
+ return ch;
+ }
+
+ // assume we're already in the right place
+ ch = UTEXT_NEXT32(fRXPat->fPattern);
+ if (ch == U_SENTINEL) {
+ return ch;
+ }
+
+ 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;
+ }
+ 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 = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
+ 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;
+ }
+ }
+ }
+ // TODO: check what Java & Perl do with non-ASCII white spaces. Ticket 6061.
+ if (PatternProps::isWhiteSpace(c.fChar) == FALSE) {
+ break;
+ }
+ c.fChar = nextCharLL();
+ }
+ }
+
+ //
+ // check for backslash escaped characters.
+ //
+ if (c.fChar == chBackSlash) {
+ int64_t pos = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
+ 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;
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fRXPat->fPattern, fPatternLength)) {
+ int32_t endIndex = (int32_t)pos;
+ c.fChar = u_unescapeAt(uregex_ucstr_unescape_charAt, &endIndex, (int32_t)fPatternLength, (void *)fRXPat->fPattern->chunkContents);
+
+ if (endIndex == pos) {
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ }
+ fCharNum += endIndex - pos;
+ UTEXT_SETNATIVEINDEX(fRXPat->fPattern, endIndex);
+ } else {
+ int32_t offset = 0;
+ struct URegexUTextUnescapeCharContext context = U_REGEX_UTEXT_UNESCAPE_CONTEXT(fRXPat->fPattern);
+
+ UTEXT_SETNATIVEINDEX(fRXPat->fPattern, pos);
+ c.fChar = u_unescapeAt(uregex_utext_unescape_charAt, &offset, INT32_MAX, &context);
+
+ if (offset == 0) {
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ } else if (context.lastOffset == offset) {
+ UTEXT_PREVIOUS32(fRXPat->fPattern);
+ } else if (context.lastOffset != offset-1) {
+ utext_moveIndex32(fRXPat->fPattern, offset - context.lastOffset - 1);
+ }
+ fCharNum += offset;
+ }
+ }
+ else if (peekCharLL() == chDigit0) {
+ // Octal Escape, using Java Regexp Conventions
+ // which are \0 followed by 1-3 octal digits.
+ // Different from ICU Unescape handling of Octal, which does not
+ // require the leading 0.
+ // Java also has the convention of only consuming 2 octal digits if
+ // the three digit number would be > 0xff
+ //
+ c.fChar = 0;
+ nextCharLL(); // Consume the initial 0.
+ int index;
+ for (index=0; index<3; index++) {
+ int32_t ch = peekCharLL();
+ if (ch<chDigit0 || ch>chDigit7) {
+ if (index==0) {
+ // \0 is not followed by any octal digits.
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ }
+ break;
+ }
+ c.fChar <<= 3;
+ c.fChar += ch&7;
+ if (c.fChar <= 255) {
+ nextCharLL();
+ } else {
+ // The last digit made the number too big. Forget we saw it.
+ c.fChar >>= 3;
+ }
+ }
+ c.fQuoted = TRUE;
+ }
+ else if (peekCharLL() == chQ) {
+ // "\Q" enter quote mode, which will continue until "\E"
+ fQuoteMode = TRUE;
+ nextCharLL(); // discard the 'Q'.
+ nextChar(c); // recurse to get the real next char.
+ }
+ 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.
+ 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);
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// scanNamedChar
+ // Get a UChar32 from a \N{UNICODE CHARACTER NAME} in the pattern.
+//
+// The scan position will be at the 'N'. On return
+// the scan position should be just after the '}'
+//
+// Return the UChar32
+//
+//------------------------------------------------------------------------------
+UChar32 RegexCompile::scanNamedChar() {
+ if (U_FAILURE(*fStatus)) {
+ return 0;
+ }
+
+ nextChar(fC);
+ if (fC.fChar != chLBrace) {
+ error(U_REGEX_PROPERTY_SYNTAX);
+ return 0;
+ }
+
+ UnicodeString charName;
+ for (;;) {
+ nextChar(fC);
+ if (fC.fChar == chRBrace) {
+ break;
+ }
+ if (fC.fChar == -1) {
+ error(U_REGEX_PROPERTY_SYNTAX);
+ return 0;
+ }
+ charName.append(fC.fChar);
+ }
+
+ char name[100];
+ if (!uprv_isInvariantUString(charName.getBuffer(), charName.length()) ||
+ (uint32_t)charName.length()>=sizeof(name)) {
+ // All Unicode character names have only invariant characters.
+ // The API to get a character, given a name, accepts only char *, forcing us to convert,
+ // which requires this error check
+ error(U_REGEX_PROPERTY_SYNTAX);
+ return 0;
+ }
+ charName.extract(0, charName.length(), name, sizeof(name), US_INV);
+
+ UChar32 theChar = u_charFromName(U_UNICODE_CHAR_NAME, name, fStatus);
+ if (U_FAILURE(*fStatus)) {
+ error(U_REGEX_PROPERTY_SYNTAX);
+ }
+
+ nextChar(fC); // Continue overall regex pattern processing with char after the '}'
+ return theChar;
+}
+
+//------------------------------------------------------------------------------
+//
+// 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 == chP);
+ UBool negated = (fC.fChar == chP);
+
+ UnicodeString propertyName;
+ nextChar(fC);
+ if (fC.fChar != chLBrace) {
+ error(U_REGEX_PROPERTY_SYNTAX);
+ return NULL;
+ }
+ for (;;) {
+ nextChar(fC);
+ if (fC.fChar == chRBrace) {
+ break;
+ }
+ if (fC.fChar == -1) {
+ // Hit the end of the input string without finding the closing '}'
+ error(U_REGEX_PROPERTY_SYNTAX);
+ return NULL;
+ }
+ propertyName.append(fC.fChar);
+ }
+ uset = createSetForProperty(propertyName, negated);
+ nextChar(fC); // Move input scan to position following the closing '}'
+ return uset;
+}
+
+//------------------------------------------------------------------------------
+//
+// scanPosixProp Construct a UnicodeSet from the text at the current scan
+// position, which is expected be of the form [:property expression:]
+//
+// The scan position will be at the opening ':'. On return
+// the scan position must be on the closing ']'
+//
+// Return a UnicodeSet constructed from the pattern,
+// or NULL if this is not a valid POSIX-style set expression.
+// If not a property expression, restore the initial scan position
+// (to the opening ':')
+//
+// Note: the opening '[:' is not sufficient to guarantee that
+// this is a [:property:] expression.
+// [:'+=,] is a perfectly good ordinary set expression that
+// happens to include ':' as one of its characters.
+//
+//------------------------------------------------------------------------------
+UnicodeSet *RegexCompile::scanPosixProp() {
+ UnicodeSet *uset = NULL;
+
+ if (U_FAILURE(*fStatus)) {
+ return NULL;
+ }
+
+ U_ASSERT(fC.fChar == chColon);
+
+ // Save the scanner state.
+ // TODO: move this into the scanner, with the state encapsulated in some way. Ticket 6062
+ int64_t savedScanIndex = fScanIndex;
+ int64_t savedNextIndex = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
+ UBool savedQuoteMode = fQuoteMode;
+ UBool savedInBackslashQuote = fInBackslashQuote;
+ UBool savedEOLComments = fEOLComments;
+ int64_t savedLineNum = fLineNum;
+ int64_t savedCharNum = fCharNum;
+ UChar32 savedLastChar = fLastChar;
+ UChar32 savedPeekChar = fPeekChar;
+ RegexPatternChar savedfC = fC;
+
+ // Scan for a closing ]. A little tricky because there are some perverse
+ // edge cases possible. "[:abc\Qdef:] \E]" is a valid non-property expression,
+ // ending on the second closing ].
+
+ UnicodeString propName;
+ UBool negated = FALSE;
+
+ // Check for and consume the '^' in a negated POSIX property, e.g. [:^Letter:]
+ nextChar(fC);
+ if (fC.fChar == chUp) {
+ negated = TRUE;
+ nextChar(fC);
+ }
+
+ // Scan for the closing ":]", collecting the property name along the way.
+ UBool sawPropSetTerminator = FALSE;
+ for (;;) {
+ propName.append(fC.fChar);
+ nextChar(fC);
+ if (fC.fQuoted || fC.fChar == -1) {
+ // Escaped characters or end of input - either says this isn't a [:Property:]
+ break;
+ }
+ if (fC.fChar == chColon) {
+ nextChar(fC);
+ if (fC.fChar == chRBracket) {
+ sawPropSetTerminator = TRUE;
+ }
+ break;
+ }
+ }
+
+ if (sawPropSetTerminator) {
+ uset = createSetForProperty(propName, negated);
+ }
+ else
+ {
+ // No closing ":]".
+ // Restore the original scan position.
+ // The main scanner will retry the input as a normal set expression,
+ // not a [:Property:] expression.
+ fScanIndex = savedScanIndex;
+ fQuoteMode = savedQuoteMode;
+ fInBackslashQuote = savedInBackslashQuote;
+ fEOLComments = savedEOLComments;
+ fLineNum = savedLineNum;
+ fCharNum = savedCharNum;
+ fLastChar = savedLastChar;
+ fPeekChar = savedPeekChar;
+ fC = savedfC;
+ UTEXT_SETNATIVEINDEX(fRXPat->fPattern, savedNextIndex);
+ }
+ return uset;
+}
+
+static inline void addIdentifierIgnorable(UnicodeSet *set, UErrorCode& ec) {
+ set->add(0, 8).add(0x0e, 0x1b).add(0x7f, 0x9f);
+ addCategory(set, U_GC_CF_MASK, ec);
+}
+
+//
+// Create a Unicode Set from a Unicode Property expression.
+// This is common code underlying both \p{...} ane [:...:] expressions.
+// Includes trying the Java "properties" that aren't supported as
+// normal ICU UnicodeSet properties
+//
+static const UChar posSetPrefix[] = {0x5b, 0x5c, 0x70, 0x7b, 0}; // "[\p{"
+static const UChar negSetPrefix[] = {0x5b, 0x5c, 0x50, 0x7b, 0}; // "[\P{"
+UnicodeSet *RegexCompile::createSetForProperty(const UnicodeString &propName, UBool negated) {
+ UnicodeString setExpr;
+ UnicodeSet *set;
+ uint32_t usetFlags = 0;
+
+ if (U_FAILURE(*fStatus)) {
+ return NULL;
+ }
+
+ //
+ // First try the property as we received it
+ //
+ if (negated) {
+ setExpr.append(negSetPrefix, -1);
+ } else {
+ setExpr.append(posSetPrefix, -1);
+ }
+ setExpr.append(propName);
+ setExpr.append(chRBrace);
+ setExpr.append(chRBracket);
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ usetFlags |= USET_CASE_INSENSITIVE;
+ }
+ set = new UnicodeSet(setExpr, usetFlags, NULL, *fStatus);
+ if (U_SUCCESS(*fStatus)) {
+ return set;
+ }
+ delete set;
+ set = NULL;
+
+ //
+ // The property as it was didn't work.
+
+ // Do [:word:]. It is not recognized as a property by UnicodeSet. "word" not standard POSIX
+ // or standard Java, but many other regular expression packages do recognize it.
+
+ if (propName.caseCompare(UNICODE_STRING_SIMPLE("word"), 0) == 0) {
+ *fStatus = U_ZERO_ERROR;
+ set = new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET]));
+ if (set == NULL) {
+ *fStatus = U_MEMORY_ALLOCATION_ERROR;
+ return set;
+ }
+ if (negated) {
+ set->complement();
+ }
+ return set;
+ }
+
+
+ // Do Java fixes -
+ // InGreek -> InGreek or Coptic, that being the official Unicode name for that block.
+ // InCombiningMarksforSymbols -> InCombiningDiacriticalMarksforSymbols.
+ //
+ // Note on Spaces: either "InCombiningMarksForSymbols" or "InCombining Marks for Symbols"
+ // is accepted by Java. The property part of the name is compared
+ // case-insenstively. The spaces must be exactly as shown, either
+ // all there, or all omitted, with exactly one at each position
+ // if they are present. From checking against JDK 1.6
+ //
+ // This code should be removed when ICU properties support the Java compatibility names
+ // (ICU 4.0?)
+ //
+ UnicodeString mPropName = propName;
+ if (mPropName.caseCompare(UNICODE_STRING_SIMPLE("InGreek"), 0) == 0) {
+ mPropName = UNICODE_STRING_SIMPLE("InGreek and Coptic");
+ }
+ if (mPropName.caseCompare(UNICODE_STRING_SIMPLE("InCombining Marks for Symbols"), 0) == 0 ||
+ mPropName.caseCompare(UNICODE_STRING_SIMPLE("InCombiningMarksforSymbols"), 0) == 0) {
+ mPropName = UNICODE_STRING_SIMPLE("InCombining Diacritical Marks for Symbols");
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("all")) == 0) {
+ mPropName = UNICODE_STRING_SIMPLE("javaValidCodePoint");
+ }
+
+ // See if the property looks like a Java "InBlockName", which
+ // we will recast as "Block=BlockName"
+ //
+ static const UChar IN[] = {0x49, 0x6E, 0}; // "In"
+ static const UChar BLOCK[] = {0x42, 0x6C, 0x6f, 0x63, 0x6b, 0x3d, 00}; // "Block="
+ if (mPropName.startsWith(IN, 2) && propName.length()>=3) {
+ setExpr.truncate(4); // Leaves "[\p{", or "[\P{"
+ setExpr.append(BLOCK, -1);
+ setExpr.append(UnicodeString(mPropName, 2)); // Property with the leading "In" removed.
+ setExpr.append(chRBrace);
+ setExpr.append(chRBracket);
+ *fStatus = U_ZERO_ERROR;
+ set = new UnicodeSet(setExpr, usetFlags, NULL, *fStatus);
+ if (U_SUCCESS(*fStatus)) {
+ return set;
+ }
+ delete set;
+ set = NULL;
+ }
+
+ if (propName.startsWith(UNICODE_STRING_SIMPLE("java")) ||
+ propName.compare(UNICODE_STRING_SIMPLE("all")) == 0)
+ {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ //setExpr.remove();
+ set = new UnicodeSet();
+ //
+ // Try the various Java specific properties.
+ // These all begin with "java"
+ //
+ if (mPropName.compare(UNICODE_STRING_SIMPLE("javaDefined")) == 0) {
+ addCategory(set, U_GC_CN_MASK, localStatus);
+ set->complement();
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaDigit")) == 0) {
+ addCategory(set, U_GC_ND_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaIdentifierIgnorable")) == 0) {
+ addIdentifierIgnorable(set, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaISOControl")) == 0) {
+ set->add(0, 0x1F).add(0x7F, 0x9F);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaJavaIdentifierPart")) == 0) {
+ addCategory(set, U_GC_L_MASK, localStatus);
+ addCategory(set, U_GC_SC_MASK, localStatus);
+ addCategory(set, U_GC_PC_MASK, localStatus);
+ addCategory(set, U_GC_ND_MASK, localStatus);
+ addCategory(set, U_GC_NL_MASK, localStatus);
+ addCategory(set, U_GC_MC_MASK, localStatus);
+ addCategory(set, U_GC_MN_MASK, localStatus);
+ addIdentifierIgnorable(set, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaJavaIdentifierStart")) == 0) {
+ addCategory(set, U_GC_L_MASK, localStatus);
+ addCategory(set, U_GC_NL_MASK, localStatus);
+ addCategory(set, U_GC_SC_MASK, localStatus);
+ addCategory(set, U_GC_PC_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLetter")) == 0) {
+ addCategory(set, U_GC_L_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLetterOrDigit")) == 0) {
+ addCategory(set, U_GC_L_MASK, localStatus);
+ addCategory(set, U_GC_ND_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLowerCase")) == 0) {
+ addCategory(set, U_GC_LL_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaMirrored")) == 0) {
+ set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaSpaceChar")) == 0) {
+ addCategory(set, U_GC_Z_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaSupplementaryCodePoint")) == 0) {
+ set->add(0x10000, UnicodeSet::MAX_VALUE);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaTitleCase")) == 0) {
+ addCategory(set, U_GC_LT_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUnicodeIdentifierStart")) == 0) {
+ addCategory(set, U_GC_L_MASK, localStatus);
+ addCategory(set, U_GC_NL_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUnicodeIdentifierPart")) == 0) {
+ addCategory(set, U_GC_L_MASK, localStatus);
+ addCategory(set, U_GC_PC_MASK, localStatus);
+ addCategory(set, U_GC_ND_MASK, localStatus);
+ addCategory(set, U_GC_NL_MASK, localStatus);
+ addCategory(set, U_GC_MC_MASK, localStatus);
+ addCategory(set, U_GC_MN_MASK, localStatus);
+ addIdentifierIgnorable(set, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUpperCase")) == 0) {
+ addCategory(set, U_GC_LU_MASK, localStatus);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaValidCodePoint")) == 0) {
+ set->add(0, UnicodeSet::MAX_VALUE);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaWhitespace")) == 0) {
+ addCategory(set, U_GC_Z_MASK, localStatus);
+ set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f));
+ set->add(9, 0x0d).add(0x1c, 0x1f);
+ }
+ else if (mPropName.compare(UNICODE_STRING_SIMPLE("all")) == 0) {
+ set->add(0, UnicodeSet::MAX_VALUE);
+ }
+
+ if (U_SUCCESS(localStatus) && !set->isEmpty()) {
+ *fStatus = U_ZERO_ERROR;
+ if (usetFlags & USET_CASE_INSENSITIVE) {
+ set->closeOver(USET_CASE_INSENSITIVE);
+ }
+ if (negated) {
+ set->complement();
+ }
+ return set;
+ }
+ delete set;
+ set = NULL;
+ }
+ error(*fStatus);
+ return NULL;
+}
+
+
+
+//
+// SetEval Part of the evaluation of [set expressions].
+// Perform any pending (stacked) operations with precedence
+// equal or greater to that of the next operator encountered
+// in the expression.
+//
+void RegexCompile::setEval(int32_t nextOp) {
+ UnicodeSet *rightOperand = NULL;
+ UnicodeSet *leftOperand = NULL;
+ for (;;) {
+ U_ASSERT(fSetOpStack.empty()==FALSE);
+ int32_t pendingSetOperation = fSetOpStack.peeki();
+ if ((pendingSetOperation&0xffff0000) < (nextOp&0xffff0000)) {
+ break;
+ }
+ fSetOpStack.popi();
+ U_ASSERT(fSetStack.empty() == FALSE);
+ rightOperand = (UnicodeSet *)fSetStack.peek();
+ switch (pendingSetOperation) {
+ case setNegation:
+ rightOperand->complement();
+ break;
+ case setCaseClose:
+ // TODO: need a simple close function. Ticket 6065
+ rightOperand->closeOver(USET_CASE_INSENSITIVE);
+ rightOperand->removeAllStrings();
+ break;
+ case setDifference1:
+ case setDifference2:
+ fSetStack.pop();
+ leftOperand = (UnicodeSet *)fSetStack.peek();
+ leftOperand->removeAll(*rightOperand);
+ delete rightOperand;
+ break;
+ case setIntersection1:
+ case setIntersection2:
+ fSetStack.pop();
+ leftOperand = (UnicodeSet *)fSetStack.peek();
+ leftOperand->retainAll(*rightOperand);
+ delete rightOperand;
+ break;
+ case setUnion:
+ fSetStack.pop();
+ leftOperand = (UnicodeSet *)fSetStack.peek();
+ leftOperand->addAll(*rightOperand);
+ delete rightOperand;
+ break;
+ default:
+ U_ASSERT(FALSE);
+ break;
+ }
+ }
+ }
+
+void RegexCompile::setPushOp(int32_t op) {
+ setEval(op);
+ fSetOpStack.push(op, *fStatus);
+ fSetStack.push(new UnicodeSet(), *fStatus);
+}
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.h b/Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.h
new file mode 100644
index 00000000000..032fdb7f9cc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexcmp.h
@@ -0,0 +1,229 @@
+//
+// regexcmp.h
+//
+// Copyright (C) 2002-2010, 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.
+//
+//--------------------------------------------------------------------------------
+struct RegexTableEl;
+class RegexPattern;
+
+
+class RegexCompile : public UMemory {
+public:
+
+ enum {
+ 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 RegexPatternChar {
+ UChar32 fChar;
+ UBool fQuoted;
+ };
+
+ RegexCompile(RegexPattern *rp, UErrorCode &e);
+
+ void compile(const UnicodeString &pat, UParseError &pp, UErrorCode &e);
+ void compile(UText *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 *scanProp();
+ UnicodeSet *scanPosixProp();
+ 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 setEval(int32_t op);
+ void setPushOp(int32_t op);
+ UChar32 scanNamedChar();
+ UnicodeSet *createSetForProperty(const UnicodeString &propName, UBool negated);
+
+
+ UErrorCode *fStatus;
+ RegexPattern *fRXPat;
+ UParseError *fParseErr;
+
+ //
+ // Data associated with low level character scanning
+ //
+ int64_t fScanIndex; // Index of current character being processed
+ // in the rule input string.
+ 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.
+ int64_t fLineNum; // Line number in input file.
+ int64_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.
+
+ int64_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.)
+
+ int64_t fNameStartPos; // Starting position of a \N{NAME} name in a
+ // pattern, valid while remainder of name is
+ // scanned.
+
+ UStack fSetStack; // Stack of UnicodeSets, used while evaluating
+ // (at compile time) set expressions within
+ // the pattern.
+ UStack fSetOpStack; // Stack of pending set operators (&&, --, union)
+
+ UChar32 fLastSetLiteral; // The last single code point added to a set.
+ // needed when "-y" is scanned, and we need
+ // to turn "x-y" into a range.
+};
+
+// Constant values to be pushed onto fSetOpStack while scanning & evalueating [set expressions]
+// The high 16 bits are the operator precedence, and the low 16 are a code for the operation itself.
+
+enum SetOperations {
+ setStart = 0 << 16 | 1,
+ setEnd = 1 << 16 | 2,
+ setNegation = 2 << 16 | 3,
+ setCaseClose = 2 << 16 | 9,
+ setDifference2 = 3 << 16 | 4, // '--' set difference operator
+ setIntersection2 = 3 << 16 | 5, // '&&' set intersection operator
+ setUnion = 4 << 16 | 6, // implicit union of adjacent items
+ setDifference1 = 4 << 16 | 7, // '-', single dash difference op, for compatibility with old UnicodeSet.
+ setIntersection1 = 4 << 16 | 8 // '&', single amp intersection op, for compatibility with old UnicodeSet.
+ };
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif // RBBISCAN_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.h b/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.h
new file mode 100644
index 00000000000..ab43137d8b6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.h
@@ -0,0 +1,504 @@
+//---------------------------------------------------------------------------------
+//
+// 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-2007 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_rule_char = 129;
+
+
+enum Regex_PatternParseAction {
+ doLiteralChar,
+ doSetEnd,
+ doBackslashA,
+ doSetBeginUnion,
+ doNOP,
+ doSetBackslash_w,
+ doSetRange,
+ doBackslashG,
+ doPerlInline,
+ doSetAddDash,
+ doIntevalLowerDigit,
+ doProperty,
+ doBackslashX,
+ doOpenAtomicParen,
+ doSetLiteralEscaped,
+ doPatFinish,
+ doSetBackslash_D,
+ doSetDifference2,
+ doNamedChar,
+ doNGPlus,
+ doOpenLookBehindNeg,
+ doIntervalError,
+ doIntervalSame,
+ doBackRef,
+ doPlus,
+ doOpenCaptureParen,
+ doMismatchedParenErr,
+ doBeginMatchMode,
+ doEscapeError,
+ doOpenNonCaptureParen,
+ doDollar,
+ doSetProp,
+ doIntervalUpperDigit,
+ doSetBegin,
+ doBackslashs,
+ doOpenLookBehind,
+ doSetMatchMode,
+ doOrOperator,
+ doCaret,
+ doMatchModeParen,
+ doStar,
+ doOpt,
+ doMatchMode,
+ doSuppressComments,
+ doPossessiveInterval,
+ doOpenLookAheadNeg,
+ doBackslashW,
+ doCloseParen,
+ doSetOpError,
+ doIntervalInit,
+ doSetFinish,
+ doSetIntersection2,
+ doNGStar,
+ doEnterQuoteMode,
+ doSetAddAmp,
+ doBackslashB,
+ doBackslashw,
+ doPossessiveOpt,
+ doSetNegate,
+ doRuleError,
+ doBackslashb,
+ doConditionalExpr,
+ doPossessivePlus,
+ doBadOpenParenType,
+ doNGInterval,
+ doSetLiteral,
+ doSetNamedChar,
+ doBackslashd,
+ doSetBeginDifference1,
+ doBackslashD,
+ doExit,
+ doSetBackslash_S,
+ doInterval,
+ doSetNoCloseError,
+ doNGOpt,
+ doSetPosixProp,
+ doBackslashS,
+ doBackslashZ,
+ doSetBeginIntersection1,
+ doSetBackslash_W,
+ doSetBackslash_d,
+ doOpenLookAhead,
+ doBadModeFlag,
+ doPatStart,
+ doSetNamedRange,
+ doPossessiveStar,
+ doEscapedLiteralChar,
+ doSetBackslash_s,
+ doBackslashz,
+ doDotAny,
+ 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, 129, 14,0, TRUE} // 3
+ , {doSetBegin, 91 /* [ */, 104, 182, TRUE} // 4
+ , {doNOP, 40 /* ( */, 27,0, TRUE} // 5
+ , {doDotAny, 46 /* . */, 14,0, TRUE} // 6
+ , {doCaret, 94 /* ^ */, 14,0, TRUE} // 7
+ , {doDollar, 36 /* $ */, 14,0, TRUE} // 8
+ , {doNOP, 92 /* \ */, 84,0, TRUE} // 9
+ , {doOrOperator, 124 /* | */, 2,0, TRUE} // 10
+ , {doCloseParen, 41 /* ) */, 255,0, TRUE} // 11
+ , {doPatFinish, 253, 2,0, FALSE} // 12
+ , {doRuleError, 255, 183,0, FALSE} // 13
+ , {doNOP, 42 /* * */, 63,0, TRUE} // 14 expr-quant
+ , {doNOP, 43 /* + */, 66,0, TRUE} // 15
+ , {doNOP, 63 /* ? */, 69,0, TRUE} // 16
+ , {doIntervalInit, 123 /* { */, 72,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 /* # */, 49, 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 /* < */, 46,0, TRUE} // 33
+ , {doNOP, 35 /* # */, 49, 2, TRUE} // 34
+ , {doBeginMatchMode, 105 /* i */, 52,0, FALSE} // 35
+ , {doBeginMatchMode, 100 /* d */, 52,0, FALSE} // 36
+ , {doBeginMatchMode, 109 /* m */, 52,0, FALSE} // 37
+ , {doBeginMatchMode, 115 /* s */, 52,0, FALSE} // 38
+ , {doBeginMatchMode, 117 /* u */, 52,0, FALSE} // 39
+ , {doBeginMatchMode, 119 /* w */, 52,0, FALSE} // 40
+ , {doBeginMatchMode, 120 /* x */, 52,0, FALSE} // 41
+ , {doBeginMatchMode, 45 /* - */, 52,0, FALSE} // 42
+ , {doConditionalExpr, 40 /* ( */, 183,0, TRUE} // 43
+ , {doPerlInline, 123 /* { */, 183,0, TRUE} // 44
+ , {doBadOpenParenType, 255, 183,0, FALSE} // 45
+ , {doOpenLookBehind, 61 /* = */, 2, 20, TRUE} // 46 open-paren-lookbehind
+ , {doOpenLookBehindNeg, 33 /* ! */, 2, 20, TRUE} // 47
+ , {doBadOpenParenType, 255, 183,0, FALSE} // 48
+ , {doNOP, 41 /* ) */, 255,0, TRUE} // 49 paren-comment
+ , {doMismatchedParenErr, 253, 183,0, FALSE} // 50
+ , {doNOP, 255, 49,0, TRUE} // 51
+ , {doMatchMode, 105 /* i */, 52,0, TRUE} // 52 paren-flag
+ , {doMatchMode, 100 /* d */, 52,0, TRUE} // 53
+ , {doMatchMode, 109 /* m */, 52,0, TRUE} // 54
+ , {doMatchMode, 115 /* s */, 52,0, TRUE} // 55
+ , {doMatchMode, 117 /* u */, 52,0, TRUE} // 56
+ , {doMatchMode, 119 /* w */, 52,0, TRUE} // 57
+ , {doMatchMode, 120 /* x */, 52,0, TRUE} // 58
+ , {doMatchMode, 45 /* - */, 52,0, TRUE} // 59
+ , {doSetMatchMode, 41 /* ) */, 2,0, TRUE} // 60
+ , {doMatchModeParen, 58 /* : */, 2, 14, TRUE} // 61
+ , {doBadModeFlag, 255, 183,0, FALSE} // 62
+ , {doNGStar, 63 /* ? */, 20,0, TRUE} // 63 quant-star
+ , {doPossessiveStar, 43 /* + */, 20,0, TRUE} // 64
+ , {doStar, 255, 20,0, FALSE} // 65
+ , {doNGPlus, 63 /* ? */, 20,0, TRUE} // 66 quant-plus
+ , {doPossessivePlus, 43 /* + */, 20,0, TRUE} // 67
+ , {doPlus, 255, 20,0, FALSE} // 68
+ , {doNGOpt, 63 /* ? */, 20,0, TRUE} // 69 quant-opt
+ , {doPossessiveOpt, 43 /* + */, 20,0, TRUE} // 70
+ , {doOpt, 255, 20,0, FALSE} // 71
+ , {doNOP, 128, 74,0, FALSE} // 72 interval-open
+ , {doIntervalError, 255, 183,0, FALSE} // 73
+ , {doIntevalLowerDigit, 128, 74,0, TRUE} // 74 interval-lower
+ , {doNOP, 44 /* , */, 78,0, TRUE} // 75
+ , {doIntervalSame, 125 /* } */, 81,0, TRUE} // 76
+ , {doIntervalError, 255, 183,0, FALSE} // 77
+ , {doIntervalUpperDigit, 128, 78,0, TRUE} // 78 interval-upper
+ , {doNOP, 125 /* } */, 81,0, TRUE} // 79
+ , {doIntervalError, 255, 183,0, FALSE} // 80
+ , {doNGInterval, 63 /* ? */, 20,0, TRUE} // 81 interval-type
+ , {doPossessiveInterval, 43 /* + */, 20,0, TRUE} // 82
+ , {doInterval, 255, 20,0, FALSE} // 83
+ , {doBackslashA, 65 /* A */, 2,0, TRUE} // 84 backslash
+ , {doBackslashB, 66 /* B */, 2,0, TRUE} // 85
+ , {doBackslashb, 98 /* b */, 2,0, TRUE} // 86
+ , {doBackslashd, 100 /* d */, 14,0, TRUE} // 87
+ , {doBackslashD, 68 /* D */, 14,0, TRUE} // 88
+ , {doBackslashG, 71 /* G */, 2,0, TRUE} // 89
+ , {doNamedChar, 78 /* N */, 14,0, FALSE} // 90
+ , {doProperty, 112 /* p */, 14,0, FALSE} // 91
+ , {doProperty, 80 /* P */, 14,0, FALSE} // 92
+ , {doEnterQuoteMode, 81 /* Q */, 2,0, TRUE} // 93
+ , {doBackslashS, 83 /* S */, 14,0, TRUE} // 94
+ , {doBackslashs, 115 /* s */, 14,0, TRUE} // 95
+ , {doBackslashW, 87 /* W */, 14,0, TRUE} // 96
+ , {doBackslashw, 119 /* w */, 14,0, TRUE} // 97
+ , {doBackslashX, 88 /* X */, 14,0, TRUE} // 98
+ , {doBackslashZ, 90 /* Z */, 2,0, TRUE} // 99
+ , {doBackslashz, 122 /* z */, 2,0, TRUE} // 100
+ , {doBackRef, 128, 14,0, TRUE} // 101
+ , {doEscapeError, 253, 183,0, FALSE} // 102
+ , {doEscapedLiteralChar, 255, 14,0, TRUE} // 103
+ , {doSetNegate, 94 /* ^ */, 107,0, TRUE} // 104 set-open
+ , {doSetPosixProp, 58 /* : */, 109,0, FALSE} // 105
+ , {doNOP, 255, 107,0, FALSE} // 106
+ , {doSetLiteral, 93 /* ] */, 122,0, TRUE} // 107 set-open2
+ , {doNOP, 255, 112,0, FALSE} // 108
+ , {doSetEnd, 93 /* ] */, 255,0, TRUE} // 109 set-posix
+ , {doNOP, 58 /* : */, 112,0, FALSE} // 110
+ , {doRuleError, 255, 183,0, FALSE} // 111
+ , {doSetEnd, 93 /* ] */, 255,0, TRUE} // 112 set-start
+ , {doSetBeginUnion, 91 /* [ */, 104, 129, TRUE} // 113
+ , {doNOP, 92 /* \ */, 172,0, TRUE} // 114
+ , {doNOP, 45 /* - */, 118,0, TRUE} // 115
+ , {doNOP, 38 /* & */, 120,0, TRUE} // 116
+ , {doSetLiteral, 255, 122,0, TRUE} // 117
+ , {doRuleError, 45 /* - */, 183,0, FALSE} // 118 set-start-dash
+ , {doSetAddDash, 255, 122,0, FALSE} // 119
+ , {doRuleError, 38 /* & */, 183,0, FALSE} // 120 set-start-amp
+ , {doSetAddAmp, 255, 122,0, FALSE} // 121
+ , {doSetEnd, 93 /* ] */, 255,0, TRUE} // 122 set-after-lit
+ , {doSetBeginUnion, 91 /* [ */, 104, 129, TRUE} // 123
+ , {doNOP, 45 /* - */, 159,0, TRUE} // 124
+ , {doNOP, 38 /* & */, 150,0, TRUE} // 125
+ , {doNOP, 92 /* \ */, 172,0, TRUE} // 126
+ , {doSetNoCloseError, 253, 183,0, FALSE} // 127
+ , {doSetLiteral, 255, 122,0, TRUE} // 128
+ , {doSetEnd, 93 /* ] */, 255,0, TRUE} // 129 set-after-set
+ , {doSetBeginUnion, 91 /* [ */, 104, 129, TRUE} // 130
+ , {doNOP, 45 /* - */, 152,0, TRUE} // 131
+ , {doNOP, 38 /* & */, 147,0, TRUE} // 132
+ , {doNOP, 92 /* \ */, 172,0, TRUE} // 133
+ , {doSetNoCloseError, 253, 183,0, FALSE} // 134
+ , {doSetLiteral, 255, 122,0, TRUE} // 135
+ , {doSetEnd, 93 /* ] */, 255,0, TRUE} // 136 set-after-range
+ , {doSetBeginUnion, 91 /* [ */, 104, 129, TRUE} // 137
+ , {doNOP, 45 /* - */, 155,0, TRUE} // 138
+ , {doNOP, 38 /* & */, 157,0, TRUE} // 139
+ , {doNOP, 92 /* \ */, 172,0, TRUE} // 140
+ , {doSetNoCloseError, 253, 183,0, FALSE} // 141
+ , {doSetLiteral, 255, 122,0, TRUE} // 142
+ , {doSetBeginUnion, 91 /* [ */, 104, 129, TRUE} // 143 set-after-op
+ , {doSetOpError, 93 /* ] */, 183,0, FALSE} // 144
+ , {doNOP, 92 /* \ */, 172,0, TRUE} // 145
+ , {doSetLiteral, 255, 122,0, TRUE} // 146
+ , {doSetBeginIntersection1, 91 /* [ */, 104, 129, TRUE} // 147 set-set-amp
+ , {doSetIntersection2, 38 /* & */, 143,0, TRUE} // 148
+ , {doSetAddAmp, 255, 122,0, FALSE} // 149
+ , {doSetIntersection2, 38 /* & */, 143,0, TRUE} // 150 set-lit-amp
+ , {doSetAddAmp, 255, 122,0, FALSE} // 151
+ , {doSetBeginDifference1, 91 /* [ */, 104, 129, TRUE} // 152 set-set-dash
+ , {doSetDifference2, 45 /* - */, 143,0, TRUE} // 153
+ , {doSetAddDash, 255, 122,0, FALSE} // 154
+ , {doSetDifference2, 45 /* - */, 143,0, TRUE} // 155 set-range-dash
+ , {doSetAddDash, 255, 122,0, FALSE} // 156
+ , {doSetIntersection2, 38 /* & */, 143,0, TRUE} // 157 set-range-amp
+ , {doSetAddAmp, 255, 122,0, FALSE} // 158
+ , {doSetDifference2, 45 /* - */, 143,0, TRUE} // 159 set-lit-dash
+ , {doSetAddDash, 91 /* [ */, 122,0, FALSE} // 160
+ , {doSetAddDash, 93 /* ] */, 122,0, FALSE} // 161
+ , {doNOP, 92 /* \ */, 164,0, TRUE} // 162
+ , {doSetRange, 255, 136,0, TRUE} // 163
+ , {doSetOpError, 115 /* s */, 183,0, FALSE} // 164 set-lit-dash-escape
+ , {doSetOpError, 83 /* S */, 183,0, FALSE} // 165
+ , {doSetOpError, 119 /* w */, 183,0, FALSE} // 166
+ , {doSetOpError, 87 /* W */, 183,0, FALSE} // 167
+ , {doSetOpError, 100 /* d */, 183,0, FALSE} // 168
+ , {doSetOpError, 68 /* D */, 183,0, FALSE} // 169
+ , {doSetNamedRange, 78 /* N */, 136,0, FALSE} // 170
+ , {doSetRange, 255, 136,0, TRUE} // 171
+ , {doSetProp, 112 /* p */, 129,0, FALSE} // 172 set-escape
+ , {doSetProp, 80 /* P */, 129,0, FALSE} // 173
+ , {doSetNamedChar, 78 /* N */, 122,0, FALSE} // 174
+ , {doSetBackslash_s, 115 /* s */, 136,0, TRUE} // 175
+ , {doSetBackslash_S, 83 /* S */, 136,0, TRUE} // 176
+ , {doSetBackslash_w, 119 /* w */, 136,0, TRUE} // 177
+ , {doSetBackslash_W, 87 /* W */, 136,0, TRUE} // 178
+ , {doSetBackslash_d, 100 /* d */, 136,0, TRUE} // 179
+ , {doSetBackslash_D, 68 /* D */, 136,0, TRUE} // 180
+ , {doSetLiteralEscaped, 255, 122,0, TRUE} // 181
+ , {doSetFinish, 255, 14,0, FALSE} // 182 set-finish
+ , {doExit, 255, 183,0, TRUE} // 183 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,
+ 0,
+ 0,
+ "open-paren-lookbehind",
+ 0,
+ 0,
+ "paren-comment",
+ 0,
+ 0,
+ "paren-flag",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "quant-star",
+ 0,
+ 0,
+ "quant-plus",
+ 0,
+ 0,
+ "quant-opt",
+ 0,
+ 0,
+ "interval-open",
+ 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,
+ "set-open",
+ 0,
+ 0,
+ "set-open2",
+ 0,
+ "set-posix",
+ 0,
+ 0,
+ "set-start",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-start-dash",
+ 0,
+ "set-start-amp",
+ 0,
+ "set-after-lit",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-after-set",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-after-range",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-after-op",
+ 0,
+ 0,
+ 0,
+ "set-set-amp",
+ 0,
+ 0,
+ "set-lit-amp",
+ 0,
+ "set-set-dash",
+ 0,
+ 0,
+ "set-range-dash",
+ 0,
+ "set-range-amp",
+ 0,
+ "set-lit-dash",
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-lit-dash-escape",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-escape",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "set-finish",
+ "errorDeath",
+ 0};
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.pl b/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.pl
new file mode 100755
index 00000000000..f1dc06af7ec
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.pl
@@ -0,0 +1,328 @@
+#!/usr/bin/perl
+# ********************************************************************
+# * COPYRIGHT:
+# * Copyright (c) 2002-2007, 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?
+#
+
+
+$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-2007 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-4.8.1/i18n/regexcst.txt b/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.txt
new file mode 100644
index 00000000000..77ebd9606b4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexcst.txt
@@ -0,0 +1,467 @@
+
+#*****************************************************************************
+#
+# Copyright (C) 2002-2007, 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 set-open ^set-finish doSetBegin
+ '(' n open-paren
+ '.' n expr-quant doDotAny
+ '^' n expr-quant doCaret
+ '$' n expr-quant 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
+ 'd' paren-flag doBeginMatchMode
+ 'm' paren-flag doBeginMatchMode
+ 's' paren-flag doBeginMatchMode
+ 'u' 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 ')'
+#
+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
+ 'd' n paren-flag doMatchMode
+ 'm' n paren-flag doMatchMode
+ 's' n paren-flag doMatchMode
+ 'u' 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:
+ 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 doNamedChar # \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 doEscapedLiteralChar
+
+
+
+#
+# [set expression] parsing,
+# All states involved in parsing set expressions have names beginning with "set-"
+#
+
+set-open:
+ '^' n set-open2 doSetNegate
+ ':' set-posix doSetPosixProp
+ default set-open2
+
+set-open2:
+ ']' n set-after-lit doSetLiteral
+ default set-start
+
+# set-posix:
+# scanned a '[:' If it really is a [:property:], doSetPosixProp will have
+# moved the scan to the closing ']'. If it wasn't a property
+# expression, the scan will still be at the opening ':', which should
+# be interpreted as a normal set expression.
+set-posix:
+ ']' n pop doSetEnd
+ ':' set-start
+ default errorDeath doRuleError # should not be possible.
+
+#
+# set-start after the [ and special case leading characters (^ and/or ]) but before
+# everything else. A '-' is literal at this point.
+#
+set-start:
+ ']' n pop doSetEnd
+ '[' n set-open ^set-after-set doSetBeginUnion
+ '\' n set-escape
+ '-' n set-start-dash
+ '&' n set-start-amp
+ default n set-after-lit doSetLiteral
+
+# set-start-dash Turn "[--" into a syntax error.
+# "[-x" is good, - and x are literals.
+#
+set-start-dash:
+ '-' errorDeath doRuleError
+ default set-after-lit doSetAddDash
+
+# set-start-amp Turn "[&&" into a syntax error.
+# "[&x" is good, & and x are literals.
+#
+set-start-amp:
+ '&' errorDeath doRuleError
+ default set-after-lit doSetAddAmp
+
+#
+# set-after-lit The last thing scanned was a literal character within a set.
+# Can be followed by anything. Single '-' or '&' are
+# literals in this context, not operators.
+set-after-lit:
+ ']' n pop doSetEnd
+ '[' n set-open ^set-after-set doSetBeginUnion
+ '-' n set-lit-dash
+ '&' n set-lit-amp
+ '\' n set-escape
+ eof errorDeath doSetNoCloseError
+ default n set-after-lit doSetLiteral
+
+set-after-set:
+ ']' n pop doSetEnd
+ '[' n set-open ^set-after-set doSetBeginUnion
+ '-' n set-set-dash
+ '&' n set-set-amp
+ '\' n set-escape
+ eof errorDeath doSetNoCloseError
+ default n set-after-lit doSetLiteral
+
+set-after-range:
+ ']' n pop doSetEnd
+ '[' n set-open ^set-after-set doSetBeginUnion
+ '-' n set-range-dash
+ '&' n set-range-amp
+ '\' n set-escape
+ eof errorDeath doSetNoCloseError
+ default n set-after-lit doSetLiteral
+
+
+# set-after-op
+# After a -- or &&
+# It is an error to close a set at this point.
+#
+set-after-op:
+ '[' n set-open ^set-after-set doSetBeginUnion
+ ']' errorDeath doSetOpError
+ '\' n set-escape
+ default n set-after-lit doSetLiteral
+
+#
+# set-set-amp
+# Have scanned [[set]&
+# Could be a '&' intersection operator, if a set follows.
+# Could be the start of a '&&' operator.
+# Otherewise is a literal.
+set-set-amp:
+ '[' n set-open ^set-after-set doSetBeginIntersection1
+ '&' n set-after-op doSetIntersection2
+ default set-after-lit doSetAddAmp
+
+
+# set-lit-amp Have scanned "[literals&"
+# Could be a start of "&&" operator or a literal
+# In [abc&[def]], the '&' is a literal
+#
+set-lit-amp:
+ '&' n set-after-op doSetIntersection2
+ default set-after-lit doSetAddAmp
+
+
+#
+# set-set-dash
+# Have scanned [set]-
+# Could be a '-' difference operator, if a [set] follows.
+# Could be the start of a '--' operator.
+# Otherewise is a literal.
+set-set-dash:
+ '[' n set-open ^set-after-set doSetBeginDifference1
+ '-' n set-after-op doSetDifference2
+ default set-after-lit doSetAddDash
+
+
+#
+# set-range-dash
+# scanned a-b- or \w-
+# any set or range like item where the trailing single '-' should
+# be literal, not a set difference operation.
+# A trailing "--" is still a difference operator.
+set-range-dash:
+ '-' n set-after-op doSetDifference2
+ default set-after-lit doSetAddDash
+
+
+set-range-amp:
+ '&' n set-after-op doSetIntersection2
+ default set-after-lit doSetAddAmp
+
+
+# set-lit-dash
+# Have scanned "[literals-" Could be a range or a -- operator or a literal
+# In [abc-[def]], the '-' is a literal (confirmed with a Java test)
+# [abc-\p{xx} the '-' is an error
+# [abc-] the '-' is a literal
+# [ab-xy] the '-' is a range
+#
+set-lit-dash:
+ '-' n set-after-op doSetDifference2
+ '[' set-after-lit doSetAddDash
+ ']' set-after-lit doSetAddDash
+ '\' n set-lit-dash-escape
+ default n set-after-range doSetRange
+
+# set-lit-dash-escape
+#
+# scanned "[literal-\"
+# Could be a range, if the \ introduces an escaped literal char or a named char.
+# Otherwise it is an error.
+#
+set-lit-dash-escape:
+ 's' errorDeath doSetOpError
+ 'S' errorDeath doSetOpError
+ 'w' errorDeath doSetOpError
+ 'W' errorDeath doSetOpError
+ 'd' errorDeath doSetOpError
+ 'D' errorDeath doSetOpError
+ 'N' set-after-range doSetNamedRange
+ default n set-after-range doSetRange
+
+
+#
+# set-escape
+# Common back-slash escape processing within set expressions
+#
+set-escape:
+ 'p' set-after-set doSetProp
+ 'P' set-after-set doSetProp
+ 'N' set-after-lit doSetNamedChar
+ 's' n set-after-range doSetBackslash_s
+ 'S' n set-after-range doSetBackslash_S
+ 'w' n set-after-range doSetBackslash_w
+ 'W' n set-after-range doSetBackslash_W
+ 'd' n set-after-range doSetBackslash_d
+ 'D' n set-after-range doSetBackslash_D
+ default n set-after-lit doSetLiteralEscaped
+
+#
+# set-finish
+# Have just encountered the final ']' that completes a [set], and
+# arrived here via a pop. From here, we exit the set parsing world, and go
+# back to generic regular expression parsing.
+#
+set-finish:
+ default expr-quant doSetFinish
+
+
+#
+# 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-4.8.1/i18n/regeximp.h b/Build/source/libs/icu/icu-4.8.1/i18n/regeximp.h
new file mode 100644
index 00000000000..3ee9102df1a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regeximp.h
@@ -0,0 +1,357 @@
+//
+// Copyright (C) 2002-2010 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, // Force a backtrack, as if a match test had failed.
+ 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, // 2 kinds, normal and non-greedy.
+ // 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_UNIX = 27, // '.' operator in UNIX_LINES mode, only \n marks end of line.
+
+ 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_CARET_M_UNIX = 30, // '^' operator, test for start of line in multi-line
+ // plus UNIX_LINES mode.
+
+ 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:
+ // bit 0:
+ // 0: Normal (. doesn't match new-line) mode.
+ // 1: . matches new-line mode.
+ // bit 1: controls what new-lines are recognized by this operation.
+ // 0: All Unicode New-lines
+ // 1: UNIX_LINES, \u000a only.
+ URX_BACKSLASH_BU = 53, // \b or \B in UREGEX_UWORD mode, using Unicode style
+ // word boundaries.
+ URX_DOLLAR_D = 54, // $ end of input test, in UNIX_LINES mode.
+ URX_DOLLAR_MD = 55 // $ end of input test, in MULTI_LINE and UNIX_LINES mode.
+
+};
+
+// 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_UNIX", \
+ "CTR_LOOP", \
+ "CTR_LOOP_NG", \
+ "URX_CARET_M_UNIX", \
+ "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", \
+ "DOLLAR_D", \
+ "DOLLAR_MD"
+
+
+//
+// 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 {
+ // Header
+ int64_t fInputIdx; // Position of next character in the input string
+ int64_t fPatIdx; // Position of next Op in the compiled pattern
+ // (int64_t for UVector64, values fit in an int32_t)
+ // Remainder
+ int64_t fExtra[1]; // Extra state, for capture group start/ends
+ // atomic parentheses, repeat counts, etc.
+ // Locations assigned at pattern compile time.
+ // Variable-length array.
+};
+// number of UVector elements in the header
+#define RESTACKFRAME_HDRCOUNT 2
+
+//
+// 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-4.8.1/i18n/regexst.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/regexst.cpp
new file mode 100644
index 00000000000..b8ad297d663
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexst.cpp
@@ -0,0 +1,294 @@
+//
+// regexst.h
+//
+// Copyright (C) 2004-2010, 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};
+
+//
+// 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};
+
+
+//
+// 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),
+fEmptyText(NULL)
+{
+ // First zero out everything
+ int i;
+ for (i=0; i<URX_LAST_SET; i++) {
+ fPropSets[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);
+
+ // Check for null pointers
+ if (fPropSets[URX_ISWORD_SET] == NULL || fPropSets[URX_ISSPACE_SET] == NULL || fPropSets[URX_GC_EXTEND] == NULL ||
+ fPropSets[URX_GC_CONTROL] == NULL || fPropSets[URX_GC_L] == NULL || fPropSets[URX_GC_V] == NULL ||
+ fPropSets[URX_GC_T] == NULL || fPropSets[URX_GC_LV] == NULL || fPropSets[URX_GC_LVT] == NULL) {
+ goto ExitConstrDeleteAll;
+ }
+ 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);
+ // Null pointer check
+ if (fPropSets[URX_GC_NORMAL] == NULL) {
+ goto ExitConstrDeleteAll;
+ }
+ 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] = UnicodeSet(UnicodeString(TRUE, gRuleSet_rule_char_pattern, -1), *status);
+ fRuleSets[kRuleSet_digit_char-128] = 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++) {
+ fRuleSets[i].compact();
+ }
+
+ // Finally, initialize an empty string for utility purposes
+ fEmptyText = utext_openUChars(NULL, NULL, 0, status);
+
+ return; // If we reached this point, everything is fine so just exit
+
+ExitConstrDeleteAll: // Remove fPropSets and fRuleSets and return error
+ for (i=0; i<URX_LAST_SET; i++) {
+ delete fPropSets[i];
+ fPropSets[i] = NULL;
+ }
+ *status = U_MEMORY_ALLOCATION_ERROR;
+}
+
+
+RegexStaticSets::~RegexStaticSets() {
+ int32_t i;
+
+ for (i=0; i<URX_LAST_SET; i++) {
+ delete fPropSets[i];
+ fPropSets[i] = NULL;
+ }
+ fRuleDigitsAlias = NULL;
+
+ utext_close(fEmptyText);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// 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 (p == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ 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-4.8.1/i18n/regexst.h b/Build/source/libs/icu/icu-4.8.1/i18n/regexst.h
new file mode 100644
index 00000000000..07034d4450a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regexst.h
@@ -0,0 +1,58 @@
+//
+// regexst.h
+//
+// Copyright (C) 2003-2010, 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"
+#include "unicode/utext.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;
+ UText *fEmptyText; // 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-4.8.1/i18n/regextxt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/regextxt.cpp
new file mode 100644
index 00000000000..6960dac1b74
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regextxt.cpp
@@ -0,0 +1,45 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2008-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+//
+// file: regextxt.cpp
+//
+// This file contains utility code for supporting UText in the regular expression engine.
+//
+
+#include "regextxt.h"
+
+U_NAMESPACE_BEGIN
+
+U_CFUNC UChar U_CALLCONV
+uregex_utext_unescape_charAt(int32_t offset, void *ct) {
+ struct URegexUTextUnescapeCharContext *context = (struct URegexUTextUnescapeCharContext *)ct;
+ UChar32 c;
+ if (offset == context->lastOffset + 1) {
+ c = UTEXT_NEXT32(context->text);
+ context->lastOffset++;
+ } else if (offset == context->lastOffset) {
+ c = UTEXT_PREVIOUS32(context->text);
+ UTEXT_NEXT32(context->text);
+ } else {
+ utext_moveIndex32(context->text, offset - context->lastOffset - 1);
+ c = UTEXT_NEXT32(context->text);
+ context->lastOffset = offset;
+ }
+
+ // !!!: Doesn't handle characters outside BMP
+ if (U_IS_BMP(c)) {
+ return (UChar)c;
+ } else {
+ return 0;
+ }
+}
+
+U_CFUNC UChar U_CALLCONV
+uregex_ucstr_unescape_charAt(int32_t offset, void *context) {
+ return ((UChar *)context)[offset];
+}
+
+U_NAMESPACE_END
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/regextxt.h b/Build/source/libs/icu/icu-4.8.1/i18n/regextxt.h
new file mode 100644
index 00000000000..5b59838a92b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/regextxt.h
@@ -0,0 +1,48 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2008-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+//
+// file: regextxt.h
+//
+// This file contains utility code for supporting UText in the regular expression engine.
+//
+// This class is internal to the regular expression implementation.
+// For the public Regular Expression API, see the file "unicode/regex.h"
+//
+
+#ifndef _REGEXTXT_H
+#define _REGEXTXT_H
+
+#include "unicode/utypes.h"
+#include "unicode/utext.h"
+
+U_NAMESPACE_BEGIN
+
+#define UTEXT_USES_U16(ut) (NULL==((ut)->pFuncs->mapNativeIndexToUTF16))
+
+#if 0
+#define REGEX_DISABLE_CHUNK_MODE 1
+#endif
+
+#ifdef REGEX_DISABLE_CHUNK_MODE
+# define UTEXT_FULL_TEXT_IN_CHUNK(ut,len) (FALSE)
+#else
+# define UTEXT_FULL_TEXT_IN_CHUNK(ut,len) ((0==((ut)->chunkNativeStart))&&((len)==((ut)->chunkNativeLimit))&&((len)==((ut)->nativeIndexingLimit)))
+#endif
+
+struct URegexUTextUnescapeCharContext {
+ UText *text;
+ int32_t lastOffset;
+};
+#define U_REGEX_UTEXT_UNESCAPE_CONTEXT(text) { (text), -1 }
+
+U_CFUNC UChar U_CALLCONV
+uregex_utext_unescape_charAt(int32_t offset, void * /* struct URegexUTextUnescapeCharContext* */ context);
+U_CFUNC UChar U_CALLCONV
+uregex_ucstr_unescape_charAt(int32_t offset, void * /* UChar* */ context);
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.cpp
new file mode 100644
index 00000000000..065b0a1e612
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.cpp
@@ -0,0 +1,482 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, 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 "unicode/smpdtfmt.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 **/
+};
+
+static const char DT_DateTimePatternsTag[]="DateTimePatterns";
+
+
+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_FULL && fTimeStyle <= UDAT_SHORT) {
+ fTimeFormat = createTimeInstance((EStyle)fTimeStyle, locale);
+ } else if(fTimeStyle != UDAT_NONE) {
+ // don't support other time styles (e.g. relative styles), 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;
+ UChar emptyStr = 0;
+ UnicodeString dateString(&emptyStr);
+
+ // calculate the difference, in days, between 'cal' and now.
+ int dayDiff = dayDifference(cal, status);
+
+ // look up string
+ int32_t len = 0;
+ const UChar *theString = getStringForDay(dayDiff, len, status);
+ if(U_SUCCESS(status) && (theString!=NULL)) {
+ // found a relative string
+ dateString.setTo(theString, len);
+ }
+
+ if(fTimeFormat == NULL || fCombinedFormat == 0) {
+ if (dateString.length() > 0) {
+ appendTo.append(dateString);
+ } else if(fDateFormat != NULL) {
+ fDateFormat->format(cal,appendTo,pos);
+ }
+ } else {
+ if (dateString.length() == 0 && fDateFormat != NULL) {
+ fDateFormat->format(cal,dateString,pos);
+ }
+ UnicodeString timeString(&emptyStr);
+ FieldPosition timepos = pos;
+ fTimeFormat->format(cal,timeString,timepos);
+ Formattable timeDateStrings[] = { timeString, dateString };
+ fCombinedFormat->format(timeDateStrings, 2, appendTo, pos, status); // pos is ignored by this
+ int32_t offset;
+ if (pos.getEndIndex() > 0 && (offset = appendTo.indexOf(dateString)) >= 0) {
+ // pos.field was found in dateString, offset start & end based on final position of dateString
+ pos.setBeginIndex( pos.getBeginIndex() + offset );
+ pos.setEndIndex( pos.getEndIndex() + offset );
+ } else if (timepos.getEndIndex() > 0 && (offset = appendTo.indexOf(timeString)) >= 0) {
+ // pos.field was found in timeString, offset start & end based on final position of timeString
+ pos.setBeginIndex( timepos.getBeginIndex() + offset );
+ pos.setEndIndex( timepos.getEndIndex() + offset );
+ }
+ }
+
+ return appendTo;
+}
+
+
+
+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.
+}
+
+UnicodeString&
+RelativeDateFormat::toPattern(UnicodeString& result, UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ result.remove();
+ if (fTimeFormat == NULL || fCombinedFormat == 0) {
+ if (fDateFormat != NULL) {
+ UnicodeString datePattern;
+ this->toPatternDate(datePattern, status);
+ if (!U_FAILURE(status)) {
+ result.setTo(datePattern);
+ }
+ }
+ } else {
+ UnicodeString datePattern, timePattern;
+ this->toPatternDate(datePattern, status);
+ this->toPatternTime(timePattern, status);
+ if (!U_FAILURE(status)) {
+ Formattable timeDatePatterns[] = { timePattern, datePattern };
+ FieldPosition pos;
+ fCombinedFormat->format(timeDatePatterns, 2, result, pos, status);
+ }
+ }
+ }
+ return result;
+}
+
+UnicodeString&
+RelativeDateFormat::toPatternDate(UnicodeString& result, UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ result.remove();
+ if ( fDateFormat ) {
+ SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fDateFormat);
+ if (sdtfmt != NULL) {
+ sdtfmt->toPattern(result);
+ } else {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ }
+ }
+ return result;
+}
+
+UnicodeString&
+RelativeDateFormat::toPatternTime(UnicodeString& result, UErrorCode& status) const
+{
+ if (!U_FAILURE(status)) {
+ result.remove();
+ if ( fTimeFormat ) {
+ SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fTimeFormat);
+ if (sdtfmt != NULL) {
+ sdtfmt->toPattern(result);
+ } else {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ }
+ }
+ return result;
+}
+
+void
+RelativeDateFormat::applyPatterns(const UnicodeString& datePattern, const UnicodeString& timePattern, UErrorCode &status)
+{
+ if (!U_FAILURE(status)) {
+ SimpleDateFormat* sdtfmt = NULL;
+ SimpleDateFormat* stmfmt = NULL;
+ if (fDateFormat && (sdtfmt = dynamic_cast<SimpleDateFormat*>(fDateFormat)) == NULL) {
+ status = U_UNSUPPORTED_ERROR;
+ return;
+ }
+ if (fTimeFormat && (stmfmt = dynamic_cast<SimpleDateFormat*>(fTimeFormat)) == NULL) {
+ status = U_UNSUPPORTED_ERROR;
+ return;
+ }
+ if ( fDateFormat ) {
+ sdtfmt->applyPattern(datePattern);
+ }
+ if ( fTimeFormat ) {
+ stmfmt->applyPattern(timePattern);
+ }
+ }
+}
+
+const DateFormatSymbols*
+RelativeDateFormat::getDateFormatSymbols() const
+{
+ SimpleDateFormat* sdtfmt = NULL;
+ if (fDateFormat && (sdtfmt = dynamic_cast<SimpleDateFormat*>(fDateFormat)) != NULL) {
+ return sdtfmt->getDateFormatSymbols();
+ }
+ return NULL;
+}
+
+void RelativeDateFormat::loadDates(UErrorCode &status) {
+ CalendarData calData(fLocale, "gregorian", status);
+
+ UErrorCode tempStatus = status;
+ UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, tempStatus);
+ if(U_SUCCESS(tempStatus)) {
+ int32_t patternsSize = ures_getSize(dateTimePatterns);
+ if (patternsSize > kDateTime) {
+ int32_t resStrLen = 0;
+
+ int32_t glueIndex = kDateTime;
+ if (patternsSize >= (DateFormat::kDateTimeOffset + DateFormat::kShort + 1)) {
+ // Get proper date time format
+ switch (fDateStyle) {
+ case kFullRelative:
+ case kFull:
+ glueIndex = kDateTimeOffset + kFull;
+ break;
+ case kLongRelative:
+ case kLong:
+ glueIndex = kDateTimeOffset + kLong;
+ break;
+ case kMediumRelative:
+ case kMedium:
+ glueIndex = kDateTimeOffset + kMedium;
+ break;
+ case kShortRelative:
+ case kShort:
+ glueIndex = kDateTimeOffset + kShort;
+ break;
+ default:
+ break;
+ }
+ }
+
+ const UChar *resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &tempStatus);
+ fCombinedFormat = new MessageFormat(UnicodeString(TRUE, resStr, resStrLen), fLocale, tempStatus);
+ }
+ }
+
+ 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? Would be difficult, don't know the calendar type
+ Calendar *nowCal = cal.clone();
+ nowCal->setTime(Calendar::getNow(), status);
+
+ // For the day difference, we are interested in the difference in the (modified) julian day number
+ // which is midnight to midnight. Using fieldDifference() is NOT correct here, because
+ // 6pm Jan 4th to 10am Jan 5th should be considered "tomorrow".
+ int32_t dayDiff = cal.get(UCAL_JULIAN_DAY, status) - nowCal->get(UCAL_JULIAN_DAY, status);
+
+ delete nowCal;
+ return dayDiff;
+}
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.h
new file mode 100644
index 00000000000..d7eed6e4582
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/reldtfmt.h
@@ -0,0 +1,312 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, 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 DateFormatSymbols;
+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);
+ *
+ * @internal ICU 3.8
+ */
+
+class RelativeDateFormat : public DateFormat {
+public:
+ RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const Locale& locale, UErrorCode& status);
+
+ // overrides
+ /**
+ * Copy constructor.
+ * @internal ICU 3.8
+ */
+ RelativeDateFormat(const RelativeDateFormat&);
+
+ /**
+ * Assignment operator.
+ * @internal ICU 3.8
+ */
+ RelativeDateFormat& operator=(const RelativeDateFormat&);
+
+ /**
+ * Destructor.
+ * @internal 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.
+ * @internal 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.
+ * @internal ICU 3.8
+ */
+ virtual UBool operator==(const Format& other) const;
+
+
+ using DateFormat::format;
+
+ /**
+ * 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.
+ * @internal 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.
+ * @internal 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.
+ * @internal 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.
+ * @internal 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.
+ * @internal ICU 3.8
+ */
+ virtual UDate parse( const UnicodeString& text,
+ UErrorCode& status) const;
+
+ /**
+ * Return a single pattern string generated by combining the patterns for the
+ * date and time formatters associated with this object.
+ * @param result Output param to receive the pattern.
+ * @return A reference to 'result'.
+ * @internal ICU 4.2 technology preview
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result, UErrorCode& status) const;
+
+ /**
+ * Get the date pattern for the the date formatter associated with this object.
+ * @param result Output param to receive the date pattern.
+ * @return A reference to 'result'.
+ * @internal ICU 4.2 technology preview
+ */
+ virtual UnicodeString& toPatternDate(UnicodeString& result, UErrorCode& status) const;
+
+ /**
+ * Get the time pattern for the the time formatter associated with this object.
+ * @param result Output param to receive the time pattern.
+ * @return A reference to 'result'.
+ * @internal ICU 4.2 technology preview
+ */
+ virtual UnicodeString& toPatternTime(UnicodeString& result, UErrorCode& status) const;
+
+ /**
+ * Apply the given unlocalized date & time pattern strings to this relative date format.
+ * (i.e., after this call, this formatter will format dates and times according to
+ * the new patterns)
+ *
+ * @param datePattern The date pattern to be applied.
+ * @param timePattern The time pattern to be applied.
+ * @internal ICU 4.2 technology preview
+ */
+ virtual void applyPatterns(const UnicodeString& datePattern, const UnicodeString& timePattern, 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.
+ * @internal ICU 4.8
+ */
+ virtual const DateFormatSymbols* getDateFormatSymbols(void) 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
+ * @internal 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.
+ * @internal 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.
+ * @internal 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-4.8.1/i18n/rematch.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/rematch.cpp
new file mode 100644
index 00000000000..7111d5495f0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/rematch.cpp
@@ -0,0 +1,6114 @@
+/*
+**************************************************************************
+* Copyright (C) 2002-2011 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 "uvectr64.h"
+#include "regeximp.h"
+#include "regexst.h"
+#include "regextxt.h"
+#include "ucase.h"
+
+// #include <malloc.h> // Needed for heapcheck testing
+
+
+// Find progress callback
+// ----------------------
+// Macro to inline test & call to ReportFindProgress(). Eliminates unnecessary function call.
+//
+#define REGEXFINDPROGRESS_INTERRUPT(pos, status) \
+ (fFindProgressCallbackFn != NULL) && (ReportFindProgress(pos, status) == FALSE)
+
+
+// Smart Backtracking
+// ------------------
+// When a failure would go back to a LOOP_C instruction,
+// strings, characters, and setrefs scan backwards for a valid start
+// character themselves, pop the stack, and save state, emulating the
+// LOOP_C's effect but assured that the next character of input is a
+// possible matching character.
+//
+// Good idea in theory; unfortunately it only helps out a few specific
+// cases and slows the engine down a little in the rest.
+
+//#define REGEX_SMART_BACKTRACKING 1
+
+U_NAMESPACE_BEGIN
+
+// Default limit for the size of the back track stack, to avoid system
+// failures causedby heap exhaustion. Units are in 32 bit words, not bytes.
+// This value puts ICU's limits higher than most other regexp implementations,
+// which use recursion rather than the heap, and take more storage per
+// backtrack point.
+//
+static const int32_t DEFAULT_BACKTRACK_STACK_CAPACITY = 8000000;
+
+// Time limit counter constant.
+// Time limits for expression evaluation are in terms of quanta of work by
+// the engine, each of which is 10,000 state saves.
+// This constant determines that state saves per tick number.
+static const int32_t TIMER_INITIAL_VALUE = 10000;
+
+//-----------------------------------------------------------------------------
+//
+// Constructor and Destructor
+//
+//-----------------------------------------------------------------------------
+RegexMatcher::RegexMatcher(const RegexPattern *pat) {
+ fDeferredStatus = U_ZERO_ERROR;
+ init(fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return;
+ }
+ if (pat==NULL) {
+ fDeferredStatus = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ fPattern = pat;
+ init2(RegexStaticSets::gStaticSets->fEmptyText, fDeferredStatus);
+}
+
+
+
+RegexMatcher::RegexMatcher(const UnicodeString &regexp, const UnicodeString &input,
+ uint32_t flags, UErrorCode &status) {
+ init(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UParseError pe;
+ fPatternOwned = RegexPattern::compile(regexp, flags, pe, status);
+ fPattern = fPatternOwned;
+
+ UText inputText = UTEXT_INITIALIZER;
+ utext_openConstUnicodeString(&inputText, &input, &status);
+ init2(&inputText, status);
+ utext_close(&inputText);
+
+ fInputUniStrMaybeMutable = TRUE;
+}
+
+
+RegexMatcher::RegexMatcher(UText *regexp, UText *input,
+ uint32_t flags, UErrorCode &status) {
+ init(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UParseError pe;
+ fPatternOwned = RegexPattern::compile(regexp, flags, pe, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ fPattern = fPatternOwned;
+ init2(input, status);
+}
+
+
+RegexMatcher::RegexMatcher(const UnicodeString &regexp,
+ uint32_t flags, UErrorCode &status) {
+ init(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UParseError pe;
+ fPatternOwned = RegexPattern::compile(regexp, flags, pe, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fPattern = fPatternOwned;
+ init2(RegexStaticSets::gStaticSets->fEmptyText, status);
+}
+
+RegexMatcher::RegexMatcher(UText *regexp,
+ uint32_t flags, UErrorCode &status) {
+ init(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UParseError pe;
+ fPatternOwned = RegexPattern::compile(regexp, flags, pe, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ fPattern = fPatternOwned;
+ init2(RegexStaticSets::gStaticSets->fEmptyText, status);
+}
+
+
+
+
+RegexMatcher::~RegexMatcher() {
+ delete fStack;
+ if (fData != fSmallData) {
+ uprv_free(fData);
+ fData = NULL;
+ }
+ if (fPatternOwned) {
+ delete fPatternOwned;
+ fPatternOwned = NULL;
+ fPattern = NULL;
+ }
+
+ if (fInput) {
+ delete fInput;
+ }
+ if (fInputText) {
+ utext_close(fInputText);
+ }
+ if (fAltInputText) {
+ utext_close(fAltInputText);
+ }
+
+ #if UCONFIG_NO_BREAK_ITERATION==0
+ delete fWordBreakItr;
+ #endif
+}
+
+//
+// init() common initialization for use by all constructors.
+// Initialize all fields, get the object into a consistent state.
+// This must be done even when the initial status shows an error,
+// so that the object is initialized sufficiently well for the destructor
+// to run safely.
+//
+void RegexMatcher::init(UErrorCode &status) {
+ fPattern = NULL;
+ fPatternOwned = NULL;
+ fFrameSize = 0;
+ fRegionStart = 0;
+ fRegionLimit = 0;
+ fAnchorStart = 0;
+ fAnchorLimit = 0;
+ fLookStart = 0;
+ fLookLimit = 0;
+ fActiveStart = 0;
+ fActiveLimit = 0;
+ fTransparentBounds = FALSE;
+ fAnchoringBounds = TRUE;
+ fMatch = FALSE;
+ fMatchStart = 0;
+ fMatchEnd = 0;
+ fLastMatchEnd = -1;
+ fAppendPosition = 0;
+ fHitEnd = FALSE;
+ fRequireEnd = FALSE;
+ fStack = NULL;
+ fFrame = NULL;
+ fTimeLimit = 0;
+ fTime = 0;
+ fTickCounter = 0;
+ fStackLimit = DEFAULT_BACKTRACK_STACK_CAPACITY;
+ fCallbackFn = NULL;
+ fCallbackContext = NULL;
+ fFindProgressCallbackFn = NULL;
+ fFindProgressCallbackContext = NULL;
+ fTraceDebug = FALSE;
+ fDeferredStatus = status;
+ fData = fSmallData;
+ fWordBreakItr = NULL;
+
+ fStack = new UVector64(status);
+ fInputText = NULL;
+ fAltInputText = NULL;
+ fInput = NULL;
+ fInputLength = 0;
+ fInputUniStrMaybeMutable = FALSE;
+
+ if (U_FAILURE(status)) {
+ fDeferredStatus = status;
+ }
+}
+
+//
+// init2() Common initialization for use by RegexMatcher constructors, part 2.
+// This handles the common setup to be done after the Pattern is available.
+//
+void RegexMatcher::init2(UText *input, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ fDeferredStatus = status;
+ return;
+ }
+
+ if (fPattern->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(fSmallData[0]))) {
+ fData = (int64_t *)uprv_malloc(fPattern->fDataSize * sizeof(int64_t));
+ if (fData == NULL) {
+ status = fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ reset(input);
+ setStackLimit(DEFAULT_BACKTRACK_STACK_CAPACITY, status);
+ if (U_FAILURE(status)) {
+ fDeferredStatus = status;
+ return;
+ }
+}
+
+
+static const UChar BACKSLASH = 0x5c;
+static const UChar DOLLARSIGN = 0x24;
+//--------------------------------------------------------------------------------
+//
+// appendReplacement
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::appendReplacement(UnicodeString &dest,
+ const UnicodeString &replacement,
+ UErrorCode &status) {
+ UText replacementText = UTEXT_INITIALIZER;
+
+ utext_openConstUnicodeString(&replacementText, &replacement, &status);
+ if (U_SUCCESS(status)) {
+ UText resultText = UTEXT_INITIALIZER;
+ utext_openUnicodeString(&resultText, &dest, &status);
+
+ if (U_SUCCESS(status)) {
+ appendReplacement(&resultText, &replacementText, status);
+ utext_close(&resultText);
+ }
+ utext_close(&replacementText);
+ }
+
+ return *this;
+}
+
+//
+// appendReplacement, UText mode
+//
+RegexMatcher &RegexMatcher::appendReplacement(UText *dest,
+ UText *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
+ int64_t destLen = utext_nativeLength(dest);
+ if (fMatchStart > fAppendPosition) {
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ destLen += utext_replace(dest, destLen, destLen, fInputText->chunkContents+fAppendPosition,
+ (int32_t)(fMatchStart-fAppendPosition), &status);
+ } else {
+ int32_t len16;
+ if (UTEXT_USES_U16(fInputText)) {
+ len16 = (int32_t)(fMatchStart-fAppendPosition);
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ len16 = utext_extract(fInputText, fAppendPosition, fMatchStart, NULL, 0, &lengthStatus);
+ }
+ UChar *inputChars = (UChar *)uprv_malloc(sizeof(UChar)*(len16+1));
+ if (inputChars == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
+ utext_extract(fInputText, fAppendPosition, fMatchStart, inputChars, len16+1, &status);
+ destLen += utext_replace(dest, destLen, destLen, inputChars, len16, &status);
+ uprv_free(inputChars);
+ }
+ }
+ fAppendPosition = 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.
+ UTEXT_SETNATIVEINDEX(replacement, 0);
+ UChar32 c = UTEXT_NEXT32(replacement);
+ while (c != U_SENTINEL) {
+ 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.
+ c = UTEXT_CURRENT32(replacement);
+ if (c == U_SENTINEL) {
+ break;
+ }
+
+ if (c==0x55/*U*/ || c==0x75/*u*/) {
+ // We have a \udddd or \Udddddddd escape sequence.
+ int32_t offset = 0;
+ struct URegexUTextUnescapeCharContext context = U_REGEX_UTEXT_UNESCAPE_CONTEXT(replacement);
+ UChar32 escapedChar = u_unescapeAt(uregex_utext_unescape_charAt, &offset, INT32_MAX, &context);
+ if (escapedChar != (UChar32)0xFFFFFFFF) {
+ if (U_IS_BMP(escapedChar)) {
+ UChar c16 = (UChar)escapedChar;
+ destLen += utext_replace(dest, destLen, destLen, &c16, 1, &status);
+ } else {
+ UChar surrogate[2];
+ surrogate[0] = U16_LEAD(escapedChar);
+ surrogate[1] = U16_TRAIL(escapedChar);
+ if (U_SUCCESS(status)) {
+ destLen += utext_replace(dest, destLen, destLen, surrogate, 2, &status);
+ }
+ }
+ // TODO: Report errors for mal-formed \u escapes?
+ // As this is, the original sequence is output, which may be OK.
+ if (context.lastOffset == offset) {
+ (void)UTEXT_PREVIOUS32(replacement);
+ } else if (context.lastOffset != offset-1) {
+ utext_moveIndex32(replacement, offset - context.lastOffset - 1);
+ }
+ }
+ } else {
+ (void)UTEXT_NEXT32(replacement);
+ // Plain backslash escape. Just put out the escaped character.
+ if (U_IS_BMP(c)) {
+ UChar c16 = (UChar)c;
+ destLen += utext_replace(dest, destLen, destLen, &c16, 1, &status);
+ } else {
+ UChar surrogate[2];
+ surrogate[0] = U16_LEAD(c);
+ surrogate[1] = U16_TRAIL(c);
+ if (U_SUCCESS(status)) {
+ destLen += utext_replace(dest, destLen, destLen, surrogate, 2, &status);
+ }
+ }
+ }
+ } else if (c != DOLLARSIGN) {
+ // Normal char, not a $. Copy it out without further checks.
+ if (U_IS_BMP(c)) {
+ UChar c16 = (UChar)c;
+ destLen += utext_replace(dest, destLen, destLen, &c16, 1, &status);
+ } else {
+ UChar surrogate[2];
+ surrogate[0] = U16_LEAD(c);
+ surrogate[1] = U16_TRAIL(c);
+ if (U_SUCCESS(status)) {
+ destLen += utext_replace(dest, destLen, destLen, surrogate, 2, &status);
+ }
+ }
+ } else {
+ // 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 (;;) {
+ digitC = UTEXT_CURRENT32(replacement);
+ if (digitC == U_SENTINEL) {
+ break;
+ }
+ if (u_isdigit(digitC) == FALSE) {
+ break;
+ }
+ (void)UTEXT_NEXT32(replacement);
+ 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.
+ UChar c16 = DOLLARSIGN;
+ destLen += utext_replace(dest, destLen, destLen, &c16, 1, &status);
+ } else {
+ // Finally, append the capture group data to the destination.
+ destLen += appendGroup(groupNum, dest, status);
+ if (U_FAILURE(status)) {
+ // Can fail if group number is out of range.
+ break;
+ }
+ }
+ }
+
+ if (U_FAILURE(status)) {
+ break;
+ } else {
+ c = UTEXT_NEXT32(replacement);
+ }
+ }
+
+ 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.
+//
+// Note: Match ranges do not affect appendTail or appendReplacement
+//
+//--------------------------------------------------------------------------------
+UnicodeString &RegexMatcher::appendTail(UnicodeString &dest) {
+ UErrorCode status = U_ZERO_ERROR;
+ UText resultText = UTEXT_INITIALIZER;
+ utext_openUnicodeString(&resultText, &dest, &status);
+
+ if (U_SUCCESS(status)) {
+ appendTail(&resultText, status);
+ utext_close(&resultText);
+ }
+
+ return dest;
+}
+
+//
+// appendTail, UText mode
+//
+UText *RegexMatcher::appendTail(UText *dest, UErrorCode &status) {
+ UBool bailOut = FALSE;
+ if (U_FAILURE(status)) {
+ bailOut = TRUE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ bailOut = TRUE;
+ }
+
+ if (bailOut) {
+ // dest must not be NULL
+ if (dest) {
+ utext_replace(dest, utext_nativeLength(dest), utext_nativeLength(dest), NULL, 0, &status);
+ return dest;
+ }
+ }
+
+ if (fInputLength > fAppendPosition) {
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ int64_t destLen = utext_nativeLength(dest);
+ utext_replace(dest, destLen, destLen, fInputText->chunkContents+fAppendPosition,
+ (int32_t)(fInputLength-fAppendPosition), &status);
+ } else {
+ int32_t len16;
+ if (UTEXT_USES_U16(fInputText)) {
+ len16 = (int32_t)(fInputLength-fAppendPosition);
+ } else {
+ len16 = utext_extract(fInputText, fAppendPosition, fInputLength, NULL, 0, &status);
+ status = U_ZERO_ERROR; // buffer overflow
+ }
+
+ UChar *inputChars = (UChar *)uprv_malloc(sizeof(UChar)*(len16));
+ if (inputChars == NULL) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ utext_extract(fInputText, fAppendPosition, fInputLength, inputChars, len16, &status); // unterminated
+ int64_t destLen = utext_nativeLength(dest);
+ utext_replace(dest, destLen, destLen, inputChars, len16, &status);
+ uprv_free(inputChars);
+ }
+ }
+ }
+ return dest;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// end
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::end(UErrorCode &err) const {
+ return end(0, err);
+}
+
+int64_t RegexMatcher::end64(UErrorCode &err) const {
+ return end64(0, err);
+}
+
+int64_t RegexMatcher::end64(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;
+ }
+ int64_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;
+}
+
+int32_t RegexMatcher::end(int32_t group, UErrorCode &err) const {
+ return (int32_t)end64(group, err);
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// 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;
+ }
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ return findUsingChunk();
+ }
+
+ int64_t startPos = fMatchEnd;
+ if (startPos==0) {
+ startPos = fActiveStart;
+ }
+
+ 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 >= fActiveLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ (void)UTEXT_NEXT32(fInputText);
+ startPos = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ } 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.)
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ }
+
+
+ // 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.
+ // Note: some patterns that cannot match anything will have fMinMatchLength==Max Int.
+ // Be aware of possible overflows if making changes here.
+ int64_t testStartLimit;
+ if (UTEXT_USES_U16(fInputText)) {
+ testStartLimit = fActiveLimit - fPattern->fMinMatchLen;
+ if (startPos > testStartLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ } else {
+ // For now, let the matcher discover that it can't match on its own
+ // We don't know how long the match len is in native characters
+ testStartLimit = fActiveLimit;
+ }
+
+ 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, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ if (startPos >= testStartLimit) {
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ (void)UTEXT_NEXT32(fInputText);
+ startPos = UTEXT_GETNATIVEINDEX(fInputText);
+ // 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 == testStartLimit the last time through.
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ U_ASSERT(FALSE);
+
+ case START_START:
+ // Matches are only possible at the start of the input string
+ // (pattern begins with ^ or \A)
+ if (startPos > fActiveStart) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ MatchAt(startPos, FALSE, 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);
+ int64_t pos;
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ for (;;) {
+ c = UTEXT_NEXT32(fInputText);
+ pos = UTEXT_GETNATIVEINDEX(fInputText);
+ // c will be -1 (U_SENTINEL) at end of text, in which case we
+ // skip this next block (so we don't have a negative array index)
+ // and handle end of text in the following block.
+ if (c >= 0 && ((c<256 && fPattern->fInitialChars8->contains(c)) ||
+ (c>=256 && fPattern->fInitialChars->contains(c)))) {
+ MatchAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, pos);
+ }
+ if (startPos >= testStartLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ startPos = pos;
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ 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;
+ int64_t pos;
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ for (;;) {
+ c = UTEXT_NEXT32(fInputText);
+ pos = UTEXT_GETNATIVEINDEX(fInputText);
+ if (c == theChar) {
+ MatchAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, pos);
+ }
+ if (startPos >= testStartLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ startPos = pos;
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ }
+ U_ASSERT(FALSE);
+
+ case START_LINE:
+ {
+ UChar32 c;
+ if (startPos == fAnchorStart) {
+ MatchAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ c = UTEXT_NEXT32(fInputText);
+ startPos = UTEXT_GETNATIVEINDEX(fInputText);
+ } else {
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ c = UTEXT_PREVIOUS32(fInputText);
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ }
+
+ if (fPattern->fFlags & UREGEX_UNIX_LINES) {
+ for (;;) {
+ if (c == 0x0a) {
+ MatchAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ }
+ if (startPos >= testStartLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ c = UTEXT_NEXT32(fInputText);
+ startPos = UTEXT_GETNATIVEINDEX(fInputText);
+ // 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 == testStartLimit the last time through.
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ } else {
+ for (;;) {
+ 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 < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) {
+ (void)UTEXT_NEXT32(fInputText);
+ startPos = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ MatchAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ UTEXT_SETNATIVEINDEX(fInputText, startPos);
+ }
+ if (startPos >= testStartLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ c = UTEXT_NEXT32(fInputText);
+ startPos = UTEXT_GETNATIVEINDEX(fInputText);
+ // 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 == testStartLimit the last time through.
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ }
+ }
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+ U_ASSERT(FALSE);
+ return FALSE;
+}
+
+
+
+UBool RegexMatcher::find(int64_t start, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ this->reset(); // Note: Reset() is specified by Java Matcher documentation.
+ // This will reset the region to be the full input length.
+ if (start < 0) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+
+ int64_t nativeStart = start;
+ if (nativeStart < fActiveStart || nativeStart > fActiveLimit) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+ fMatchEnd = nativeStart;
+ return find();
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// findUsingChunk() -- like find(), but with the advance knowledge that the
+// entire string is available in the UText's chunk buffer.
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::findUsingChunk() {
+ // Start at the position of the last match end. (Will be zero if the
+ // matcher has been reset.
+ //
+
+ int32_t startPos = (int32_t)fMatchEnd;
+ if (startPos==0) {
+ startPos = (int32_t)fActiveStart;
+ }
+
+ const UChar *inputBuf = fInputText->chunkContents;
+
+ 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 >= fActiveLimit) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ U16_FWD_1(inputBuf, startPos, fInputLength);
+ }
+ } 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.)
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ }
+
+
+ // 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.
+ // Note: some patterns that cannot match anything will have fMinMatchLength==Max Int.
+ // Be aware of possible overflows if making changes here.
+ int32_t testLen = (int32_t)(fActiveLimit - fPattern->fMinMatchLen);
+ if (startPos > testLen) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+
+ 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 (;;) {
+ MatchChunkAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ if (startPos >= testLen) {
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ U16_FWD_1(inputBuf, startPos, fActiveLimit);
+ // 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.
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ U_ASSERT(FALSE);
+
+ case START_START:
+ // Matches are only possible at the start of the input string
+ // (pattern begins with ^ or \A)
+ if (startPos > fActiveStart) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ MatchChunkAt(startPos, FALSE, 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, fActiveLimit, c); // like c = inputBuf[startPos++];
+ if ((c<256 && fPattern->fInitialChars8->contains(c)) ||
+ (c>=256 && fPattern->fInitialChars->contains(c))) {
+ MatchChunkAt(pos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (pos >= testLen) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ 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, fActiveLimit, c); // like c = inputBuf[startPos++];
+ if (c == theChar) {
+ MatchChunkAt(pos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (pos >= testLen) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ }
+ U_ASSERT(FALSE);
+
+ case START_LINE:
+ {
+ UChar32 c;
+ if (startPos == fAnchorStart) {
+ MatchChunkAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ U16_FWD_1(inputBuf, startPos, fActiveLimit);
+ }
+
+ if (fPattern->fFlags & UREGEX_UNIX_LINES) {
+ for (;;) {
+ c = inputBuf[startPos-1];
+ if (c == 0x0a) {
+ MatchChunkAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (startPos >= testLen) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ U16_FWD_1(inputBuf, startPos, fActiveLimit);
+ // 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.
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ } else {
+ 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 < fActiveLimit && inputBuf[startPos] == 0x0a) {
+ startPos++;
+ }
+ MatchChunkAt(startPos, FALSE, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (startPos >= testLen) {
+ fMatch = FALSE;
+ fHitEnd = TRUE;
+ return FALSE;
+ }
+ U16_FWD_1(inputBuf, startPos, fActiveLimit);
+ // 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.
+ if (REGEXFINDPROGRESS_INTERRUPT(startPos, fDeferredStatus))
+ return FALSE;
+ }
+ }
+ }
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+ U_ASSERT(FALSE);
+ return FALSE;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// group()
+//
+//--------------------------------------------------------------------------------
+UnicodeString RegexMatcher::group(UErrorCode &status) const {
+ return group(0, status);
+}
+
+// Return immutable shallow clone
+UText *RegexMatcher::group(UText *dest, int64_t &group_len, UErrorCode &status) const {
+ return group(0, dest, group_len, status);
+}
+
+// Return immutable shallow clone
+UText *RegexMatcher::group(int32_t groupNum, UText *dest, int64_t &group_len, UErrorCode &status) const {
+ group_len = 0;
+ UBool bailOut = FALSE;
+ if (U_FAILURE(status)) {
+ return dest;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ bailOut = TRUE;
+ }
+ if (fMatch == FALSE) {
+ status = U_REGEX_INVALID_STATE;
+ bailOut = TRUE;
+ }
+ if (groupNum < 0 || groupNum > fPattern->fGroupMap->size()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ bailOut = TRUE;
+ }
+
+ if (bailOut) {
+ return (dest) ? dest : utext_openUChars(NULL, NULL, 0, &status);
+ }
+
+ int64_t s, e;
+ if (groupNum == 0) {
+ s = fMatchStart;
+ e = fMatchEnd;
+ } else {
+ int32_t groupOffset = fPattern->fGroupMap->elementAti(groupNum-1);
+ U_ASSERT(groupOffset < fPattern->fFrameSize);
+ U_ASSERT(groupOffset >= 0);
+ s = fFrame->fExtra[groupOffset];
+ e = fFrame->fExtra[groupOffset+1];
+ }
+
+ if (s < 0) {
+ // A capture group wasn't part of the match
+ return utext_clone(dest, fInputText, FALSE, TRUE, &status);
+ }
+ U_ASSERT(s <= e);
+ group_len = e - s;
+
+ dest = utext_clone(dest, fInputText, FALSE, TRUE, &status);
+ if (dest)
+ UTEXT_SETNATIVEINDEX(dest, s);
+ return dest;
+}
+
+UnicodeString RegexMatcher::group(int32_t groupNum, UErrorCode &status) const {
+ UnicodeString result;
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ UText resultText = UTEXT_INITIALIZER;
+ utext_openUnicodeString(&resultText, &result, &status);
+ group(groupNum, &resultText, status);
+ utext_close(&resultText);
+ return result;
+}
+
+
+// Return deep (mutable) clone
+// Technology Preview (as an API), but note that the UnicodeString API is implemented
+// using this function.
+UText *RegexMatcher::group(int32_t groupNum, UText *dest, UErrorCode &status) const {
+ UBool bailOut = FALSE;
+ if (U_FAILURE(status)) {
+ return dest;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ bailOut = TRUE;
+ }
+
+ if (fMatch == FALSE) {
+ status = U_REGEX_INVALID_STATE;
+ bailOut = TRUE;
+ }
+ if (groupNum < 0 || groupNum > fPattern->fGroupMap->size()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ bailOut = TRUE;
+ }
+
+ if (bailOut) {
+ if (dest) {
+ utext_replace(dest, 0, utext_nativeLength(dest), NULL, 0, &status);
+ return dest;
+ } else {
+ return utext_openUChars(NULL, NULL, 0, &status);
+ }
+ }
+
+ int64_t s, e;
+ if (groupNum == 0) {
+ s = fMatchStart;
+ e = fMatchEnd;
+ } else {
+ int32_t groupOffset = fPattern->fGroupMap->elementAti(groupNum-1);
+ U_ASSERT(groupOffset < fPattern->fFrameSize);
+ U_ASSERT(groupOffset >= 0);
+ s = fFrame->fExtra[groupOffset];
+ e = fFrame->fExtra[groupOffset+1];
+ }
+
+ if (s < 0) {
+ // A capture group wasn't part of the match
+ if (dest) {
+ utext_replace(dest, 0, utext_nativeLength(dest), NULL, 0, &status);
+ return dest;
+ } else {
+ return utext_openUChars(NULL, NULL, 0, &status);
+ }
+ }
+ U_ASSERT(s <= e);
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ U_ASSERT(e <= fInputLength);
+ if (dest) {
+ utext_replace(dest, 0, utext_nativeLength(dest), fInputText->chunkContents+s, (int32_t)(e-s), &status);
+ } else {
+ UText groupText = UTEXT_INITIALIZER;
+ utext_openUChars(&groupText, fInputText->chunkContents+s, e-s, &status);
+ dest = utext_clone(NULL, &groupText, TRUE, FALSE, &status);
+ utext_close(&groupText);
+ }
+ } else {
+ int32_t len16;
+ if (UTEXT_USES_U16(fInputText)) {
+ len16 = (int32_t)(e-s);
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ len16 = utext_extract(fInputText, s, e, NULL, 0, &lengthStatus);
+ }
+ UChar *groupChars = (UChar *)uprv_malloc(sizeof(UChar)*(len16+1));
+ if (groupChars == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return dest;
+ }
+ utext_extract(fInputText, s, e, groupChars, len16+1, &status);
+
+ if (dest) {
+ utext_replace(dest, 0, utext_nativeLength(dest), groupChars, len16, &status);
+ } else {
+ UText groupText = UTEXT_INITIALIZER;
+ utext_openUChars(&groupText, groupChars, len16, &status);
+ dest = utext_clone(NULL, &groupText, TRUE, FALSE, &status);
+ utext_close(&groupText);
+ }
+
+ uprv_free(groupChars);
+ }
+ return dest;
+}
+
+//--------------------------------------------------------------------------------
+//
+// appendGroup() -- currently internal only, appends a group to a UText rather
+// than replacing its contents
+//
+//--------------------------------------------------------------------------------
+
+int64_t RegexMatcher::appendGroup(int32_t groupNum, UText *dest, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return 0;
+ }
+ int64_t destLen = utext_nativeLength(dest);
+
+ if (fMatch == FALSE) {
+ status = U_REGEX_INVALID_STATE;
+ return utext_replace(dest, destLen, destLen, NULL, 0, &status);
+ }
+ if (groupNum < 0 || groupNum > fPattern->fGroupMap->size()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return utext_replace(dest, destLen, destLen, NULL, 0, &status);
+ }
+
+ int64_t s, e;
+ if (groupNum == 0) {
+ s = fMatchStart;
+ e = fMatchEnd;
+ } else {
+ int32_t groupOffset = fPattern->fGroupMap->elementAti(groupNum-1);
+ U_ASSERT(groupOffset < fPattern->fFrameSize);
+ U_ASSERT(groupOffset >= 0);
+ s = fFrame->fExtra[groupOffset];
+ e = fFrame->fExtra[groupOffset+1];
+ }
+
+ if (s < 0) {
+ // A capture group wasn't part of the match
+ return utext_replace(dest, destLen, destLen, NULL, 0, &status);
+ }
+ U_ASSERT(s <= e);
+
+ int64_t deltaLen;
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ U_ASSERT(e <= fInputLength);
+ deltaLen = utext_replace(dest, destLen, destLen, fInputText->chunkContents+s, (int32_t)(e-s), &status);
+ } else {
+ int32_t len16;
+ if (UTEXT_USES_U16(fInputText)) {
+ len16 = (int32_t)(e-s);
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ len16 = utext_extract(fInputText, s, e, NULL, 0, &lengthStatus);
+ }
+ UChar *groupChars = (UChar *)uprv_malloc(sizeof(UChar)*(len16+1));
+ if (groupChars == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ utext_extract(fInputText, s, e, groupChars, len16+1, &status);
+
+ deltaLen = utext_replace(dest, destLen, destLen, groupChars, len16, &status);
+ uprv_free(groupChars);
+ }
+ return deltaLen;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// groupCount()
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::groupCount() const {
+ return fPattern->fGroupMap->size();
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// hasAnchoringBounds()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::hasAnchoringBounds() const {
+ return fAnchoringBounds;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// hasTransparentBounds()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::hasTransparentBounds() const {
+ return fTransparentBounds;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// hitEnd()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::hitEnd() const {
+ return fHitEnd;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// input()
+//
+//--------------------------------------------------------------------------------
+const UnicodeString &RegexMatcher::input() const {
+ if (!fInput) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len16;
+ if (UTEXT_USES_U16(fInputText)) {
+ len16 = (int32_t)fInputLength;
+ } else {
+ len16 = utext_extract(fInputText, 0, fInputLength, NULL, 0, &status);
+ status = U_ZERO_ERROR; // overflow, length status
+ }
+ UnicodeString *result = new UnicodeString(len16, 0, 0);
+
+ UChar *inputChars = result->getBuffer(len16);
+ utext_extract(fInputText, 0, fInputLength, inputChars, len16, &status); // unterminated warning
+ result->releaseBuffer(len16);
+
+ (*(const UnicodeString **)&fInput) = result; // pointer assignment, rather than operator=
+ }
+
+ return *fInput;
+}
+
+//--------------------------------------------------------------------------------
+//
+// inputText()
+//
+//--------------------------------------------------------------------------------
+UText *RegexMatcher::inputText() const {
+ return fInputText;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// getInput() -- like inputText(), but makes a clone or copies into another UText
+//
+//--------------------------------------------------------------------------------
+UText *RegexMatcher::getInput (UText *dest, UErrorCode &status) const {
+ UBool bailOut = FALSE;
+ if (U_FAILURE(status)) {
+ return dest;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ bailOut = TRUE;
+ }
+
+ if (bailOut) {
+ if (dest) {
+ utext_replace(dest, 0, utext_nativeLength(dest), NULL, 0, &status);
+ return dest;
+ } else {
+ return utext_clone(NULL, fInputText, FALSE, TRUE, &status);
+ }
+ }
+
+ if (dest) {
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ utext_replace(dest, 0, utext_nativeLength(dest), fInputText->chunkContents, (int32_t)fInputLength, &status);
+ } else {
+ int32_t input16Len;
+ if (UTEXT_USES_U16(fInputText)) {
+ input16Len = (int32_t)fInputLength;
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ input16Len = utext_extract(fInputText, 0, fInputLength, NULL, 0, &lengthStatus); // buffer overflow error
+ }
+ UChar *inputChars = (UChar *)uprv_malloc(sizeof(UChar)*(input16Len));
+ if (inputChars == NULL) {
+ return dest;
+ }
+
+ status = U_ZERO_ERROR;
+ utext_extract(fInputText, 0, fInputLength, inputChars, input16Len, &status); // not terminated warning
+ status = U_ZERO_ERROR;
+ utext_replace(dest, 0, utext_nativeLength(dest), inputChars, input16Len, &status);
+
+ uprv_free(inputChars);
+ }
+ return dest;
+ } else {
+ return utext_clone(NULL, fInputText, FALSE, TRUE, &status);
+ }
+}
+
+
+static UBool compat_SyncMutableUTextContents(UText *ut);
+static UBool compat_SyncMutableUTextContents(UText *ut) {
+ UBool retVal = FALSE;
+
+ // In the following test, we're really only interested in whether the UText should switch
+ // between heap and stack allocation. If length hasn't changed, we won't, so the chunkContents
+ // will still point to the correct data.
+ if (utext_nativeLength(ut) != ut->nativeIndexingLimit) {
+ UnicodeString *us=(UnicodeString *)ut->context;
+
+ // Update to the latest length.
+ // For example, (utext_nativeLength(ut) != ut->nativeIndexingLimit).
+ int32_t newLength = us->length();
+
+ // Update the chunk description.
+ // The buffer may have switched between stack- and heap-based.
+ ut->chunkContents = us->getBuffer();
+ ut->chunkLength = newLength;
+ ut->chunkNativeLimit = newLength;
+ ut->nativeIndexingLimit = newLength;
+ retVal = TRUE;
+ }
+
+ return retVal;
+}
+
+//--------------------------------------------------------------------------------
+//
+// lookingAt()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::lookingAt(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+
+ if (fInputUniStrMaybeMutable) {
+ if (compat_SyncMutableUTextContents(fInputText)) {
+ fInputLength = utext_nativeLength(fInputText);
+ reset();
+ }
+ }
+ else {
+ resetPreserveRegion();
+ }
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ MatchChunkAt((int32_t)fActiveStart, FALSE, status);
+ } else {
+ MatchAt(fActiveStart, FALSE, status);
+ }
+ return fMatch;
+}
+
+
+UBool RegexMatcher::lookingAt(int64_t start, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ reset();
+
+ if (start < 0) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+
+ if (fInputUniStrMaybeMutable) {
+ if (compat_SyncMutableUTextContents(fInputText)) {
+ fInputLength = utext_nativeLength(fInputText);
+ reset();
+ }
+ }
+
+ int64_t nativeStart;
+ nativeStart = start;
+ if (nativeStart < fActiveStart || nativeStart > fActiveLimit) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ MatchChunkAt((int32_t)nativeStart, FALSE, status);
+ } else {
+ MatchAt(nativeStart, FALSE, status);
+ }
+ return fMatch;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// matches()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::matches(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+
+ if (fInputUniStrMaybeMutable) {
+ if (compat_SyncMutableUTextContents(fInputText)) {
+ fInputLength = utext_nativeLength(fInputText);
+ reset();
+ }
+ }
+ else {
+ resetPreserveRegion();
+ }
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ MatchChunkAt((int32_t)fActiveStart, TRUE, status);
+ } else {
+ MatchAt(fActiveStart, TRUE, status);
+ }
+ return fMatch;
+}
+
+
+UBool RegexMatcher::matches(int64_t start, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ reset();
+
+ if (start < 0) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+
+ if (fInputUniStrMaybeMutable) {
+ if (compat_SyncMutableUTextContents(fInputText)) {
+ fInputLength = utext_nativeLength(fInputText);
+ reset();
+ }
+ }
+
+ int64_t nativeStart;
+ nativeStart = start;
+ if (nativeStart < fActiveStart || nativeStart > fActiveLimit) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fInputText, fInputLength)) {
+ MatchChunkAt((int32_t)nativeStart, TRUE, status);
+ } else {
+ MatchAt(nativeStart, TRUE, status);
+ }
+ return fMatch;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// pattern
+//
+//--------------------------------------------------------------------------------
+const RegexPattern &RegexMatcher::pattern() const {
+ return *fPattern;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// region
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::region(int64_t regionStart, int64_t regionLimit, int64_t startIndex, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+
+ if (regionStart>regionLimit || regionStart<0 || regionLimit<0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ int64_t nativeStart = regionStart;
+ int64_t nativeLimit = regionLimit;
+ if (nativeStart > fInputLength || nativeLimit > fInputLength) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ if (startIndex == -1)
+ this->reset();
+ else
+ resetPreserveRegion();
+
+ fRegionStart = nativeStart;
+ fRegionLimit = nativeLimit;
+ fActiveStart = nativeStart;
+ fActiveLimit = nativeLimit;
+
+ if (startIndex != -1) {
+ if (startIndex < fActiveStart || startIndex > fActiveLimit) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ }
+ fMatchEnd = startIndex;
+ }
+
+ if (!fTransparentBounds) {
+ fLookStart = nativeStart;
+ fLookLimit = nativeLimit;
+ }
+ if (fAnchoringBounds) {
+ fAnchorStart = nativeStart;
+ fAnchorLimit = nativeLimit;
+ }
+ return *this;
+}
+
+RegexMatcher &RegexMatcher::region(int64_t start, int64_t limit, UErrorCode &status) {
+ return region(start, limit, -1, status);
+}
+
+//--------------------------------------------------------------------------------
+//
+// regionEnd
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::regionEnd() const {
+ return (int32_t)fRegionLimit;
+}
+
+int64_t RegexMatcher::regionEnd64() const {
+ return fRegionLimit;
+}
+
+//--------------------------------------------------------------------------------
+//
+// regionStart
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::regionStart() const {
+ return (int32_t)fRegionStart;
+}
+
+int64_t RegexMatcher::regionStart64() const {
+ return fRegionStart;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// replaceAll
+//
+//--------------------------------------------------------------------------------
+UnicodeString RegexMatcher::replaceAll(const UnicodeString &replacement, UErrorCode &status) {
+ UText replacementText = UTEXT_INITIALIZER;
+ UText resultText = UTEXT_INITIALIZER;
+ UnicodeString resultString;
+ if (U_FAILURE(status)) {
+ return resultString;
+ }
+
+ utext_openConstUnicodeString(&replacementText, &replacement, &status);
+ utext_openUnicodeString(&resultText, &resultString, &status);
+
+ replaceAll(&replacementText, &resultText, status);
+
+ utext_close(&resultText);
+ utext_close(&replacementText);
+
+ return resultString;
+}
+
+
+//
+// replaceAll, UText mode
+//
+UText *RegexMatcher::replaceAll(UText *replacement, UText *dest, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return dest;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return dest;
+ }
+
+ if (dest == NULL) {
+ UnicodeString emptyString;
+ UText empty = UTEXT_INITIALIZER;
+
+ utext_openUnicodeString(&empty, &emptyString, &status);
+ dest = utext_clone(NULL, &empty, TRUE, FALSE, &status);
+ utext_close(&empty);
+ }
+
+ if (U_SUCCESS(status)) {
+ reset();
+ while (find()) {
+ appendReplacement(dest, replacement, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+ appendTail(dest, status);
+ }
+
+ return dest;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// replaceFirst
+//
+//--------------------------------------------------------------------------------
+UnicodeString RegexMatcher::replaceFirst(const UnicodeString &replacement, UErrorCode &status) {
+ UText replacementText = UTEXT_INITIALIZER;
+ UText resultText = UTEXT_INITIALIZER;
+ UnicodeString resultString;
+
+ utext_openConstUnicodeString(&replacementText, &replacement, &status);
+ utext_openUnicodeString(&resultText, &resultString, &status);
+
+ replaceFirst(&replacementText, &resultText, status);
+
+ utext_close(&resultText);
+ utext_close(&replacementText);
+
+ return resultString;
+}
+
+//
+// replaceFirst, UText mode
+//
+UText *RegexMatcher::replaceFirst(UText *replacement, UText *dest, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return dest;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return dest;
+ }
+
+ reset();
+ if (!find()) {
+ return getInput(dest, status);
+ }
+
+ if (dest == NULL) {
+ UnicodeString emptyString;
+ UText empty = UTEXT_INITIALIZER;
+
+ utext_openUnicodeString(&empty, &emptyString, &status);
+ dest = utext_clone(NULL, &empty, TRUE, FALSE, &status);
+ utext_close(&empty);
+ }
+
+ appendReplacement(dest, replacement, status);
+ appendTail(dest, status);
+
+ return dest;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// requireEnd
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::requireEnd() const {
+ return fRequireEnd;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// reset
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::reset() {
+ fRegionStart = 0;
+ fRegionLimit = fInputLength;
+ fActiveStart = 0;
+ fActiveLimit = fInputLength;
+ fAnchorStart = 0;
+ fAnchorLimit = fInputLength;
+ fLookStart = 0;
+ fLookLimit = fInputLength;
+ resetPreserveRegion();
+ return *this;
+}
+
+
+
+void RegexMatcher::resetPreserveRegion() {
+ fMatchStart = 0;
+ fMatchEnd = 0;
+ fLastMatchEnd = -1;
+ fAppendPosition = 0;
+ fMatch = FALSE;
+ fHitEnd = FALSE;
+ fRequireEnd = FALSE;
+ fTime = 0;
+ fTickCounter = TIMER_INITIAL_VALUE;
+ //resetStack(); // more expensive than it looks...
+}
+
+
+RegexMatcher &RegexMatcher::reset(const UnicodeString &input) {
+ fInputText = utext_openConstUnicodeString(fInputText, &input, &fDeferredStatus);
+ if (fPattern->fNeedsAltInput) {
+ fAltInputText = utext_clone(fAltInputText, fInputText, FALSE, TRUE, &fDeferredStatus);
+ }
+ fInputLength = utext_nativeLength(fInputText);
+
+ reset();
+ delete fInput;
+ fInput = NULL;
+
+ // Do the following for any UnicodeString.
+ // This is for compatibility for those clients who modify the input string "live" during regex operations.
+ fInputUniStrMaybeMutable = TRUE;
+
+ if (fWordBreakItr != NULL) {
+#if UCONFIG_NO_BREAK_ITERATION==0
+ UErrorCode status = U_ZERO_ERROR;
+ fWordBreakItr->setText(fInputText, status);
+#endif
+ }
+ return *this;
+}
+
+
+RegexMatcher &RegexMatcher::reset(UText *input) {
+ if (fInputText != input) {
+ fInputText = utext_clone(fInputText, input, FALSE, TRUE, &fDeferredStatus);
+ if (fPattern->fNeedsAltInput) fAltInputText = utext_clone(fAltInputText, fInputText, FALSE, TRUE, &fDeferredStatus);
+ fInputLength = utext_nativeLength(fInputText);
+
+ delete fInput;
+ fInput = NULL;
+
+ if (fWordBreakItr != NULL) {
+#if UCONFIG_NO_BREAK_ITERATION==0
+ UErrorCode status = U_ZERO_ERROR;
+ fWordBreakItr->setText(input, status);
+#endif
+ }
+ }
+ reset();
+ fInputUniStrMaybeMutable = FALSE;
+
+ return *this;
+}
+
+/*RegexMatcher &RegexMatcher::reset(const UChar *) {
+ fDeferredStatus = U_INTERNAL_PROGRAM_ERROR;
+ return *this;
+}*/
+
+RegexMatcher &RegexMatcher::reset(int64_t position, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ reset(); // Reset also resets the region to be the entire string.
+
+ if (position < 0 || position > fActiveLimit) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return *this;
+ }
+ fMatchEnd = position;
+ return *this;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// refresh
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::refreshInputText(UText *input, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (input == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ if (utext_nativeLength(fInputText) != utext_nativeLength(input)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ int64_t pos = utext_getNativeIndex(fInputText);
+ // Shallow read-only clone of the new UText into the existing input UText
+ fInputText = utext_clone(fInputText, input, FALSE, TRUE, &status);
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ utext_setNativeIndex(fInputText, pos);
+
+ if (fAltInputText != NULL) {
+ pos = utext_getNativeIndex(fAltInputText);
+ fAltInputText = utext_clone(fAltInputText, input, FALSE, TRUE, &status);
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ utext_setNativeIndex(fAltInputText, pos);
+ }
+ 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)
+{
+ UText inputText = UTEXT_INITIALIZER;
+ utext_openConstUnicodeString(&inputText, &input, &status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ UText **destText = (UText **)uprv_malloc(sizeof(UText*)*destCapacity);
+ if (destText == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ int32_t i;
+ for (i = 0; i < destCapacity; i++) {
+ destText[i] = utext_openUnicodeString(NULL, &dest[i], &status);
+ }
+
+ int32_t fieldCount = split(&inputText, destText, destCapacity, status);
+
+ for (i = 0; i < destCapacity; i++) {
+ utext_close(destText[i]);
+ }
+
+ uprv_free(destText);
+ utext_close(&inputText);
+ return fieldCount;
+}
+
+//
+// split, UText mode
+//
+int32_t RegexMatcher::split(UText *input,
+ UText *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);
+ int64_t nextOutputStringStart = 0;
+ if (fActiveLimit == 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 == destCapacity 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;
+ if (fActiveLimit > nextOutputStringStart) {
+ if (UTEXT_FULL_TEXT_IN_CHUNK(input, fInputLength)) {
+ if (dest[i]) {
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]),
+ input->chunkContents+nextOutputStringStart,
+ (int32_t)(fActiveLimit-nextOutputStringStart), &status);
+ } else {
+ UText remainingText = UTEXT_INITIALIZER;
+ utext_openUChars(&remainingText, input->chunkContents+nextOutputStringStart,
+ fActiveLimit-nextOutputStringStart, &status);
+ dest[i] = utext_clone(NULL, &remainingText, TRUE, FALSE, &status);
+ utext_close(&remainingText);
+ }
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ int32_t remaining16Length =
+ utext_extract(input, nextOutputStringStart, fActiveLimit, NULL, 0, &lengthStatus);
+ UChar *remainingChars = (UChar *)uprv_malloc(sizeof(UChar)*(remaining16Length+1));
+ if (remainingChars == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+ utext_extract(input, nextOutputStringStart, fActiveLimit, remainingChars, remaining16Length+1, &status);
+ if (dest[i]) {
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]), remainingChars, remaining16Length, &status);
+ } else {
+ UText remainingText = UTEXT_INITIALIZER;
+ utext_openUChars(&remainingText, remainingChars, remaining16Length, &status);
+ dest[i] = utext_clone(NULL, &remainingText, TRUE, FALSE, &status);
+ utext_close(&remainingText);
+ }
+
+ uprv_free(remainingChars);
+ }
+ }
+ 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.
+ if (UTEXT_FULL_TEXT_IN_CHUNK(input, fInputLength)) {
+ if (dest[i]) {
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]),
+ input->chunkContents+nextOutputStringStart,
+ (int32_t)(fMatchStart-nextOutputStringStart), &status);
+ } else {
+ UText remainingText = UTEXT_INITIALIZER;
+ utext_openUChars(&remainingText, input->chunkContents+nextOutputStringStart,
+ fMatchStart-nextOutputStringStart, &status);
+ dest[i] = utext_clone(NULL, &remainingText, TRUE, FALSE, &status);
+ utext_close(&remainingText);
+ }
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ int32_t remaining16Length = utext_extract(input, nextOutputStringStart, fMatchStart, NULL, 0, &lengthStatus);
+ UChar *remainingChars = (UChar *)uprv_malloc(sizeof(UChar)*(remaining16Length+1));
+ if (remainingChars == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ utext_extract(input, nextOutputStringStart, fMatchStart, remainingChars, remaining16Length+1, &status);
+ if (dest[i]) {
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]), remainingChars, remaining16Length, &status);
+ } else {
+ UText remainingText = UTEXT_INITIALIZER;
+ utext_openUChars(&remainingText, remainingChars, remaining16Length, &status);
+ dest[i] = utext_clone(NULL, &remainingText, TRUE, FALSE, &status);
+ utext_close(&remainingText);
+ }
+
+ uprv_free(remainingChars);
+ }
+ 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-2) {
+ // Never fill the last available output string with capture group text.
+ // It will filled with the last field, the remainder of the
+ // unsplit input text.
+ break;
+ }
+ i++;
+ dest[i] = group(groupNum, dest[i], status);
+ }
+
+ if (nextOutputStringStart == fActiveLimit) {
+ // The delimiter was at the end of the string. We're done, but first
+ // we output one last empty string, for the empty field following
+ // the delimiter at the end of input.
+ if (i+1 < destCapacity) {
+ ++i;
+ if (dest[i] == NULL) {
+ dest[i] = utext_openUChars(NULL, NULL, 0, &status);
+ } else {
+ static UChar emptyString[] = {(UChar)0};
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]), emptyString, 0, &status);
+ }
+ }
+ 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.
+ if (UTEXT_FULL_TEXT_IN_CHUNK(input, fInputLength)) {
+ if (dest[i]) {
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]),
+ input->chunkContents+nextOutputStringStart,
+ (int32_t)(fActiveLimit-nextOutputStringStart), &status);
+ } else {
+ UText remainingText = UTEXT_INITIALIZER;
+ utext_openUChars(&remainingText, input->chunkContents+nextOutputStringStart,
+ fActiveLimit-nextOutputStringStart, &status);
+ dest[i] = utext_clone(NULL, &remainingText, TRUE, FALSE, &status);
+ utext_close(&remainingText);
+ }
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ int32_t remaining16Length = utext_extract(input, nextOutputStringStart, fActiveLimit, NULL, 0, &lengthStatus);
+ UChar *remainingChars = (UChar *)uprv_malloc(sizeof(UChar)*(remaining16Length+1));
+ if (remainingChars == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+ utext_extract(input, nextOutputStringStart, fActiveLimit, remainingChars, remaining16Length+1, &status);
+ if (dest[i]) {
+ utext_replace(dest[i], 0, utext_nativeLength(dest[i]), remainingChars, remaining16Length, &status);
+ } else {
+ UText remainingText = UTEXT_INITIALIZER;
+ utext_openUChars(&remainingText, remainingChars, remaining16Length, &status);
+ dest[i] = utext_clone(NULL, &remainingText, TRUE, FALSE, &status);
+ utext_close(&remainingText);
+ }
+
+ uprv_free(remainingChars);
+ }
+ break;
+ }
+ if (U_FAILURE(status)) {
+ break;
+ }
+ } // end of for loop
+ return i+1;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// start
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::start(UErrorCode &status) const {
+ return start(0, status);
+}
+
+int64_t RegexMatcher::start64(UErrorCode &status) const {
+ return start64(0, status);
+}
+
+//--------------------------------------------------------------------------------
+//
+// start(int32_t group, UErrorCode &status)
+//
+//--------------------------------------------------------------------------------
+
+int64_t RegexMatcher::start64(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;
+ }
+ int64_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;
+}
+
+
+int32_t RegexMatcher::start(int32_t group, UErrorCode &status) const {
+ return (int32_t)start64(group, status);
+}
+
+//--------------------------------------------------------------------------------
+//
+// useAnchoringBounds
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::useAnchoringBounds(UBool b) {
+ fAnchoringBounds = b;
+ fAnchorStart = (fAnchoringBounds ? fRegionStart : 0);
+ fAnchorLimit = (fAnchoringBounds ? fRegionLimit : fInputLength);
+ return *this;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// useTransparentBounds
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::useTransparentBounds(UBool b) {
+ fTransparentBounds = b;
+ fLookStart = (fTransparentBounds ? 0 : fRegionStart);
+ fLookLimit = (fTransparentBounds ? fInputLength : fRegionLimit);
+ return *this;
+}
+
+//--------------------------------------------------------------------------------
+//
+// setTimeLimit
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setTimeLimit(int32_t limit, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return;
+ }
+ if (limit < 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ fTimeLimit = limit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// getTimeLimit
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::getTimeLimit() const {
+ return fTimeLimit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// setStackLimit
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setStackLimit(int32_t limit, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return;
+ }
+ if (limit < 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ // Reset the matcher. This is needed here in case there is a current match
+ // whose final stack frame (containing the match results, pointed to by fFrame)
+ // would be lost by resizing to a smaller stack size.
+ reset();
+
+ if (limit == 0) {
+ // Unlimited stack expansion
+ fStack->setMaxCapacity(0);
+ } else {
+ // Change the units of the limit from bytes to ints, and bump the size up
+ // to be big enough to hold at least one stack frame for the pattern,
+ // if it isn't there already.
+ int32_t adjustedLimit = limit / sizeof(int32_t);
+ if (adjustedLimit < fPattern->fFrameSize) {
+ adjustedLimit = fPattern->fFrameSize;
+ }
+ fStack->setMaxCapacity(adjustedLimit);
+ }
+ fStackLimit = limit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// getStackLimit
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::getStackLimit() const {
+ return fStackLimit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// setMatchCallback
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setMatchCallback(URegexMatchCallback *callback,
+ const void *context,
+ UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fCallbackFn = callback;
+ fCallbackContext = context;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// getMatchCallback
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::getMatchCallback(URegexMatchCallback *&callback,
+ const void *&context,
+ UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ callback = fCallbackFn;
+ context = fCallbackContext;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// setMatchCallback
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setFindProgressCallback(URegexFindProgressCallback *callback,
+ const void *context,
+ UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fFindProgressCallbackFn = callback;
+ fFindProgressCallbackContext = context;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// getMatchCallback
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::getFindProgressCallback(URegexFindProgressCallback *&callback,
+ const void *&context,
+ UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ callback = fFindProgressCallbackFn;
+ context = fFindProgressCallbackContext;
+}
+
+
+//================================================================================
+//
+// 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 with all -1 data. The -1s are needed for capture group limits,
+ // where they indicate that a group has not yet matched anything.
+ fStack->removeAllElements();
+
+ REStackFrame *iFrame = (REStackFrame *)fStack->reserveBlock(fPattern->fFrameSize, fDeferredStatus);
+ int32_t i;
+ for (i=0; i<fPattern->fFrameSize-RESTACKFRAME_HDRCOUNT; i++) {
+ iFrame->fExtra[i] = -1;
+ }
+ return 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
+//
+// TODO: double-check edge cases at region boundaries.
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::isWordBoundary(int64_t pos) {
+ UBool isBoundary = FALSE;
+ UBool cIsWord = FALSE;
+
+ if (pos >= fLookLimit) {
+ fHitEnd = TRUE;
+ } else {
+ // 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.
+ UTEXT_SETNATIVEINDEX(fInputText, pos);
+ UChar32 c = UTEXT_CURRENT32(fInputText);
+ 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;
+ for (;;) {
+ if (UTEXT_GETNATIVEINDEX(fInputText) <= fLookStart) {
+ break;
+ }
+ UChar32 prevChar = UTEXT_PREVIOUS32(fInputText);
+ 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;
+}
+
+UBool RegexMatcher::isChunkWordBoundary(int32_t pos) {
+ UBool isBoundary = FALSE;
+ UBool cIsWord = FALSE;
+
+ const UChar *inputBuf = fInputText->chunkContents;
+
+ if (pos >= fLookLimit) {
+ fHitEnd = TRUE;
+ } else {
+ // 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.
+ UChar32 c;
+ U16_GET(inputBuf, fLookStart, pos, fLookLimit, c);
+ 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;
+ for (;;) {
+ if (pos <= fLookStart) {
+ break;
+ }
+ UChar32 prevChar;
+ U16_PREV(inputBuf, fLookStart, pos, prevChar);
+ 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(int64_t pos) {
+ UBool returnVal = FALSE;
+#if UCONFIG_NO_BREAK_ITERATION==0
+
+ // If we haven't yet created a break iterator for this matcher, do it now.
+ if (fWordBreakItr == NULL) {
+ fWordBreakItr =
+ (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::getEnglish(), fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ fWordBreakItr->setText(fInputText, fDeferredStatus);
+ }
+
+ if (pos >= fLookLimit) {
+ fHitEnd = TRUE;
+ returnVal = TRUE; // With Unicode word rules, only positions within the interior of "real"
+ // words are not boundaries. All non-word chars stand by themselves,
+ // with word boundaries on both sides.
+ } else {
+ if (!UTEXT_USES_U16(fInputText)) {
+ // !!!: Would like a better way to do this!
+ UErrorCode status = U_ZERO_ERROR;
+ pos = utext_extract(fInputText, 0, pos, NULL, 0, &status);
+ }
+ returnVal = fWordBreakItr->isBoundary((int32_t)pos);
+ }
+#endif
+ return returnVal;
+}
+
+//--------------------------------------------------------------------------------
+//
+// IncrementTime This function is called once each TIMER_INITIAL_VALUE state
+// saves. Increment the "time" counter, and call the
+// user callback function if there is one installed.
+//
+// If the match operation needs to be aborted, either for a time-out
+// or because the user callback asked for it, just set an error status.
+// The engine will pick that up and stop in its outer loop.
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::IncrementTime(UErrorCode &status) {
+ fTickCounter = TIMER_INITIAL_VALUE;
+ fTime++;
+ if (fCallbackFn != NULL) {
+ if ((*fCallbackFn)(fCallbackContext, fTime) == FALSE) {
+ status = U_REGEX_STOPPED_BY_CALLER;
+ return;
+ }
+ }
+ if (fTimeLimit > 0 && fTime >= fTimeLimit) {
+ status = U_REGEX_TIME_OUT;
+ }
+}
+
+//--------------------------------------------------------------------------------
+//
+// ReportFindProgress This function is called once for each advance in the target
+// string from the find() function, and calls the user progress callback
+// function if there is one installed.
+//
+// NOTE:
+//
+// If the match operation needs to be aborted because the user
+// callback asked for it, just set an error status.
+// The engine will pick that up and stop in its outer loop.
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::ReportFindProgress(int64_t matchIndex, UErrorCode &status) {
+ if (fFindProgressCallbackFn != NULL) {
+ if ((*fFindProgressCallbackFn)(fFindProgressCallbackContext, matchIndex) == FALSE) {
+ status = U_ZERO_ERROR /*U_REGEX_STOPPED_BY_CALLER*/;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+//--------------------------------------------------------------------------------
+//
+// 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.
+//
+// Parameters:
+// fp The top frame pointer when called. At return, a new
+// fame will be present
+// savePatIdx An index into the compiled pattern. Goes into the original
+// (not new) frame. If execution ever back-tracks out of the
+// new frame, this will be where we continue from in the pattern.
+// Return
+// The new frame pointer.
+//
+//--------------------------------------------------------------------------------
+inline REStackFrame *RegexMatcher::StateSave(REStackFrame *fp, int64_t savePatIdx, UErrorCode &status) {
+ // push storage for a new frame.
+ int64_t *newFP = fStack->reserveBlock(fFrameSize, status);
+ if (newFP == NULL) {
+ // Failure on attempted stack expansion.
+ // Stack function set some other error code, change it to a more
+ // specific one for regular expressions.
+ status = U_REGEX_STACK_OVERFLOW;
+ // We need to return a writable stack frame, so just return the
+ // previous frame. The match operation will stop quickly
+ // because of the error status, after which the frame will never
+ // be looked at again.
+ return fp;
+ }
+ fp = (REStackFrame *)(newFP - fFrameSize); // in case of realloc of stack.
+
+ // New stack frame = copy of old top frame.
+ int64_t *source = (int64_t *)fp;
+ int64_t *dest = newFP;
+ for (;;) {
+ *dest++ = *source++;
+ if (source == newFP) {
+ break;
+ }
+ }
+
+ fTickCounter--;
+ if (fTickCounter <= 0) {
+ IncrementTime(status); // Re-initializes fTickCounter
+ }
+ fp->fPatIdx = savePatIdx;
+ return (REStackFrame *)newFP;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// MatchAt This is the actual matching engine.
+//
+// startIdx: begin matching a this index.
+// toEnd: if true, match must extend to end of the input region
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
+ UBool isMatch = FALSE; // True if the we have a match.
+
+ int64_t backSearchIndex = U_INT64_MAX; // used after greedy single-character matches for searching backwards
+
+ 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=%ld)\n", startIdx);
+ printf("Original Pattern: ");
+ UChar32 c = utext_next32From(fPattern->fPattern, 0);
+ while (c != U_SENTINEL) {
+ if (c<32 || c>256) {
+ c = '.';
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("%c", c));
+
+ c = UTEXT_NEXT32(fPattern->fPattern);
+ }
+ printf("\n");
+ printf("Input String: ");
+ c = utext_next32From(fInputText, 0);
+ while (c != U_SENTINEL) {
+ if (c<32 || c>256) {
+ c = '.';
+ }
+ printf("%c", c);
+
+ c = UTEXT_NEXT32(fInputText);
+ }
+ printf("\n");
+ printf("\n");
+ }
+ #endif
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Cache frequently referenced items from the compiled pattern
+ //
+ int64_t *pat = fPattern->fCompiledPat->getBuffer();
+
+ const UChar *litText = fPattern->fLiteralText.getBuffer();
+ UVector *sets = fPattern->fSets;
+
+ fFrameSize = fPattern->fFrameSize;
+ REStackFrame *fp = resetStack();
+
+ 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 = (int32_t)pat[fp->fPatIdx];
+ opType = URX_TYPE(op);
+ opValue = URX_VAL(op);
+ #ifdef REGEX_RUN_DEBUG
+ if (fTraceDebug) {
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ printf("inputIdx=%d inputChar=%x sp=%3d activeLimit=%d ", fp->fInputIdx,
+ UTEXT_CURRENT32(fInputText), (int64_t *)fp-fStack->getBuffer(), fActiveLimit);
+ 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(fFrameSize);
+ break;
+
+
+ case URX_ONECHAR:
+ if (fp->fInputIdx < fActiveLimit) {
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if (c == opValue) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ break;
+ }
+ } else {
+ fHitEnd = TRUE;
+ }
+
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ UBool success = FALSE;
+ UChar32 c = UTEXT_PREVIOUS32(fInputText);
+ while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex) {
+ if (c == opValue) {
+ success = TRUE;
+ break;
+ } else if (c == U_SENTINEL) {
+ break;
+ }
+ c = UTEXT_PREVIOUS32(fInputText);
+ }
+ if (success) {
+ fHitEnd = FALSE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ 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 = (int32_t)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);
+
+ const UChar *patternChars = litText+stringStartIdx;
+ const UChar *patternEnd = patternChars+stringLen;
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c;
+ UBool success = TRUE;
+
+ while (patternChars < patternEnd && success) {
+ c = UTEXT_NEXT32(fInputText);
+
+ if (c != U_SENTINEL && UTEXT_GETNATIVEINDEX(fInputText) <= fActiveLimit) {
+ if (U_IS_BMP(c)) {
+ success = (*patternChars == c);
+ patternChars += 1;
+ } else if (patternChars+1 < patternEnd) {
+ success = (*patternChars == U16_LEAD(c) && *(patternChars+1) == U16_TRAIL(c));
+ patternChars += 2;
+ }
+ } else {
+ success = FALSE;
+ fHitEnd = TRUE; // TODO: See ticket 6074
+ }
+ }
+
+ if (success) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ } else {
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size()) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Reset to last start point
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ patternChars = litText+stringStartIdx;
+
+ // Search backwards for a possible start
+ do {
+ c = UTEXT_PREVIOUS32(fInputText);
+ if (c == U_SENTINEL) {
+ break;
+ } else if ((U_IS_BMP(c) && *patternChars == c) ||
+ (*patternChars == U16_LEAD(c) && *(patternChars+1) == U16_TRAIL(c))) {
+ success = TRUE;
+ break;
+ }
+ } while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex);
+
+ // And try again
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_STATE_SAVE:
+ fp = StateSave(fp, opValue, 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.
+ if (toEnd && fp->fInputIdx != fActiveLimit) {
+ // The pattern matched, but not to the end of input. Try some more.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+ isMatch = TRUE;
+ goto breakFromLoop;
+
+ // Start and End Capture stack frame variables are laid out 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 < fFrameSize-3);
+ fp->fExtra[opValue+2] = fp->fInputIdx;
+ break;
+
+
+ case URX_END_CAPTURE:
+ U_ASSERT(opValue >= 0 && opValue < fFrameSize-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 >= fAnchorLimit) {
+ // We really are at the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ // If we are positioned just before a new-line that is located at the
+ // end of input, succeed.
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if (UTEXT_GETNATIVEINDEX(fInputText) >= fAnchorLimit) {
+ if ((c>=0x0a && c<=0x0d) || c==0x85 || c==0x2028 || c==0x2029) {
+ // If not in the middle of a CR/LF sequence
+ if ( !(c==0x0a && fp->fInputIdx>fAnchorStart && ((void)UTEXT_PREVIOUS32(fInputText), UTEXT_PREVIOUS32(fInputText))==0x0d)) {
+ // At new-line at end of input. Success
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+
+ break;
+ }
+ }
+ } else {
+ UChar32 nextC = UTEXT_NEXT32(fInputText);
+ if (c == 0x0d && nextC == 0x0a && UTEXT_GETNATIVEINDEX(fInputText) >= fAnchorLimit) {
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break; // At CR/LF at end of input. Success
+ }
+ }
+
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_DOLLAR_D: // $, test for End of Line, in UNIX_LINES mode.
+ if (fp->fInputIdx >= fAnchorLimit) {
+ // Off the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ } else {
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ // Either at the last character of input, or off the end.
+ if (c == 0x0a && UTEXT_GETNATIVEINDEX(fInputText) == fAnchorLimit) {
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+ }
+
+ // Not at end of input. Back-track out.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+
+
+ case URX_DOLLAR_M: // $, test for End of line in multi-line mode
+ {
+ if (fp->fInputIdx >= fAnchorLimit) {
+ // We really are at the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+ // If we are positioned just before a new-line, succeed.
+ // It makes no difference where the new-line is within the input.
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c = UTEXT_CURRENT32(fInputText);
+ if ((c>=0x0a && c<=0x0d) || 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
+ // In multi-line mode, hitting a new-line just before the end of input does not
+ // set the hitEnd or requireEnd flags
+ if ( !(c==0x0a && fp->fInputIdx>fAnchorStart && UTEXT_PREVIOUS32(fInputText)==0x0d)) {
+ break;
+ }
+ }
+ // not at a new line. Fail.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_DOLLAR_MD: // $, test for End of line in multi-line and UNIX_LINES mode
+ {
+ if (fp->fInputIdx >= fAnchorLimit) {
+ // We really are at the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE; // Java set requireEnd in this case, even though
+ break; // adding a new-line would not lose the match.
+ }
+ // If we are not positioned just before a new-line, the test fails; backtrack out.
+ // It makes no difference where the new-line is within the input.
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ if (UTEXT_CURRENT32(fInputText) != 0x0a) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_CARET: // ^, test for start of line
+ if (fp->fInputIdx != fAnchorStart) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_CARET_M: // ^, test for start of line in mulit-line mode
+ {
+ if (fp->fInputIdx == fAnchorStart) {
+ // 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
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c = UTEXT_PREVIOUS32(fInputText);
+ if ((fp->fInputIdx < fAnchorLimit) &&
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ // It's a new-line. ^ is true. Success.
+ // TODO: what should be done with positions between a CR and LF?
+ break;
+ }
+ // Not at the start of a line. Fail.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_CARET_M_UNIX: // ^, test for start of line in mulit-line + Unix-line mode
+ {
+ U_ASSERT(fp->fInputIdx >= fAnchorStart);
+ if (fp->fInputIdx <= fAnchorStart) {
+ // We are at the start input. Success.
+ break;
+ }
+ // Check whether character just before the current pos is a new-line
+ U_ASSERT(fp->fInputIdx <= fAnchorLimit);
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c = UTEXT_PREVIOUS32(fInputText);
+ if (c != 0x0a) {
+ // Not at the start of a line. Back-track out.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ 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(fFrameSize);
+ }
+ }
+ 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(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_BACKSLASH_D: // Test for decimal digit
+ {
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ int8_t ctype = u_charType(c); // TODO: make a unicode set for this. Will be faster.
+ UBool success = (ctype == U_DECIMAL_DIGIT_NUMBER);
+ success ^= (opValue != 0); // flip sense for \D
+ if (success) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_BACKSLASH_G: // Test for position at end of previous match
+ if (!((fMatch && fp->fInputIdx==fMatchEnd) || (fMatch==FALSE && fp->fInputIdx==fActiveStart))) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ 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 >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ // Examine (and consume) the current char.
+ // Dispatch into a little state machine, based on the char.
+ UChar32 c;
+ c = UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ 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 >= fActiveLimit) goto GC_Done;
+ c = UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ 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;
+ (void)UTEXT_PREVIOUS32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ goto GC_Extend;
+
+GC_V:
+ if (fp->fInputIdx >= fActiveLimit) goto GC_Done;
+ c = UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (sets[URX_GC_V]->contains(c)) goto GC_V;
+ if (sets[URX_GC_T]->contains(c)) goto GC_T;
+ (void)UTEXT_PREVIOUS32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ goto GC_Extend;
+
+GC_T:
+ if (fp->fInputIdx >= fActiveLimit) goto GC_Done;
+ c = UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (sets[URX_GC_T]->contains(c)) goto GC_T;
+ (void)UTEXT_PREVIOUS32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ goto GC_Extend;
+
+GC_Extend:
+ // Combining characters are consumed here
+ for (;;) {
+ if (fp->fInputIdx >= fActiveLimit) {
+ break;
+ }
+ c = UTEXT_CURRENT32(fInputText);
+ if (sets[URX_GC_EXTEND]->contains(c) == FALSE) {
+ break;
+ }
+ (void)UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ 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 < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) {
+ c = UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+
+GC_Done:
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ }
+ break;
+ }
+
+
+
+
+ case URX_BACKSLASH_Z: // Test for end of Input
+ if (fp->fInputIdx < fAnchorLimit) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ } else {
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ }
+ 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 >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UBool success = ((opValue & URX_NEG_SET) == URX_NEG_SET);
+ opValue &= ~URX_NEG_SET;
+ U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ 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->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ } else {
+ // the character wasn't in the set.
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Try to find it, backwards
+ UTEXT_PREVIOUS32(fInputText); // skip the first character we tried
+ success = ((opValue & URX_NEG_SET) == URX_NEG_SET); // reset
+ do {
+ c = UTEXT_PREVIOUS32(fInputText);
+ if (c == U_SENTINEL) {
+ break;
+ } else 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;
+ }
+ }
+ } while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex && !success);
+
+ if (success && c != U_SENTINEL) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ 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 >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
+ if (s8->contains(c) == FALSE) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ break;
+ }
+ } else {
+ const UnicodeSet *s = fPattern->fStaticSets[opValue];
+ if (s->contains(c) == FALSE) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ break;
+ }
+ }
+ // the character wasn't in the set.
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Try to find it, backwards
+ UTEXT_PREVIOUS32(fInputText); // skip the first character we tried
+ UBool success = FALSE;
+ do {
+ c = UTEXT_PREVIOUS32(fInputText);
+ if (c == U_SENTINEL) {
+ break;
+ } else if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
+ if (s8->contains(c) == FALSE) {
+ success = TRUE;
+ break;
+ }
+ } else {
+ const UnicodeSet *s = fPattern->fStaticSets[opValue];
+ if (s->contains(c) == FALSE) {
+ success = TRUE;
+ break;
+ }
+ }
+ } while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex);
+
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_SETREF:
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ } else {
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ // There is input left. Pick up one char and test it for set membership.
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ U_ASSERT(opValue > 0 && opValue < sets->size());
+ if (c<256) {
+ Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+ if (s8->contains(c)) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ break;
+ }
+ } else {
+ UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ if (s->contains(c)) {
+ // The character is in the set. A Match.
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ break;
+ }
+ }
+
+ // the character wasn't in the set.
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Try to find it, backwards
+ UTEXT_PREVIOUS32(fInputText); // skip the first character we tried
+ UBool success = FALSE;
+ do {
+ c = UTEXT_PREVIOUS32(fInputText);
+ if (c == U_SENTINEL) {
+ break;
+ } else if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+ if (s8->contains(c)) {
+ success = TRUE;
+ break;
+ }
+ } else {
+ UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ if (s->contains(c)) {
+ success = TRUE;
+ break;
+ }
+ }
+ } while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex);
+
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_DOTANY:
+ {
+ // . matches anything, but stops at end-of-line.
+ if (fp->fInputIdx >= fActiveLimit) {
+ // At end of input. Match failed. Backtrack out.
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ // There is input left. Advance over one char, unless we've hit end-of-line
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ 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(fFrameSize);
+ break;
+ }
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ break;
+
+
+ case URX_DOTANY_ALL:
+ {
+ // ., in dot-matches-all (including new lines) mode
+ if (fp->fInputIdx >= fActiveLimit) {
+ // At end of input. Match failed. Backtrack out.
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ // There is input left. Advance over one char, except if we are
+ // at a cr/lf, advance over both of them.
+ UChar32 c;
+ c = UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (c==0x0d && fp->fInputIdx < fActiveLimit) {
+ // In the case of a CR/LF, we need to advance over both.
+ UChar32 nextc = UTEXT_CURRENT32(fInputText);
+ if (nextc == 0x0a) {
+ (void)UTEXT_NEXT32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ }
+ }
+ break;
+
+
+ case URX_DOTANY_UNIX:
+ {
+ // '.' operator, matches all, but stops at end-of-line.
+ // UNIX_LINES mode, so 0x0a is the only recognized line ending.
+ if (fp->fInputIdx >= fActiveLimit) {
+ // At end of input. Match failed. Backtrack out.
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ // There is input left. Advance over one char, unless we've hit end-of-line
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if (c == 0x0a) {
+ // End of line in normal mode. '.' does not match the \n
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ } else {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ }
+ 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, 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 = (int32_t)pat[opValue-1];
+ U_ASSERT(URX_TYPE(stoOp) == URX_STO_INP_LOC);
+ int32_t frameLoc = URX_VAL(stoOp);
+ U_ASSERT(frameLoc >= 0 && frameLoc < fFrameSize);
+ int64_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, 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 < fFrameSize-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 = (int32_t)fp->fPatIdx;
+ fp->fPatIdx += 3;
+ int32_t loopLoc = URX_VAL(pat[instrOperandLoc]);
+ int32_t minCount = (int32_t)pat[instrOperandLoc+1];
+ int32_t maxCount = (int32_t)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, status);
+ }
+ if (maxCount == 0) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+ case URX_CTR_LOOP:
+ {
+ U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
+ int32_t initOp = (int32_t)pat[opValue];
+ U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT);
+ int64_t *pCounter = &fp->fExtra[URX_VAL(initOp)];
+ int32_t minCount = (int32_t)pat[opValue+2];
+ int32_t maxCount = (int32_t)pat[opValue+3];
+ // Increment the counter. Note: we DIDN'T worry about counter
+ // overflow, since the data comes from UnicodeStrings, which
+ // stores its length in an int32_t. Do we have to think about
+ // this now that we're using UText? Probably not, since the length
+ // in UChar32s is still an int32_t.
+ (*pCounter)++;
+ U_ASSERT(*pCounter > 0);
+ if ((uint64_t)*pCounter >= (uint32_t)maxCount) {
+ U_ASSERT(*pCounter == maxCount || maxCount == -1);
+ break;
+ }
+ if (*pCounter >= minCount) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx = opValue + 4; // Loop back.
+ }
+ break;
+
+ case URX_CTR_INIT_NG:
+ {
+ // Initialize a non-greedy loop
+ U_ASSERT(opValue >= 0 && opValue < fFrameSize-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 = (int32_t)fp->fPatIdx;
+ fp->fPatIdx += 3;
+ int32_t loopLoc = URX_VAL(pat[instrOperandLoc]);
+ int32_t minCount = (int32_t)pat[instrOperandLoc+1];
+ int32_t maxCount = (int32_t)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, status);
+ }
+ fp->fPatIdx = loopLoc+1; // Continue with stuff after repeated block
+ }
+ }
+ break;
+
+ case URX_CTR_LOOP_NG:
+ {
+ // Non-greedy {min, max} loops
+ U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
+ int32_t initOp = (int32_t)pat[opValue];
+ U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT_NG);
+ int64_t *pCounter = &fp->fExtra[URX_VAL(initOp)];
+ int32_t minCount = (int32_t)pat[opValue+2];
+ int32_t maxCount = (int32_t)pat[opValue+3];
+ // Increment the counter. Note: we DIDN'T worry about counter
+ // overflow, since the data comes from UnicodeStrings, which
+ // stores its length in an int32_t. Do we have to think about
+ // this now that we're using UText? Probably not, since the length
+ // in UChar32s is still an int32_t.
+ (*pCounter)++;
+ U_ASSERT(*pCounter > 0);
+
+ if ((uint64_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, status);
+ }
+ }
+ break;
+
+ 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 = (int32_t)fData[opValue];
+ U_ASSERT(newStackSize <= fStack->size());
+ int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
+ if (newFP == (int64_t *)fp) {
+ break;
+ }
+ int32_t i;
+ for (i=0; i<fFrameSize; i++) {
+ newFP[i] = ((int64_t *)fp)[i];
+ }
+ fp = (REStackFrame *)newFP;
+ fStack->setSize(newStackSize);
+ }
+ break;
+
+ case URX_BACKREF:
+ case URX_BACKREF_I:
+ {
+ U_ASSERT(opValue < fFrameSize);
+ int64_t groupStartIdx = fp->fExtra[opValue];
+ int64_t groupEndIdx = fp->fExtra[opValue+1];
+ U_ASSERT(groupStartIdx <= groupEndIdx);
+ if (groupStartIdx < 0) {
+ // This capture group has not participated in the match thus far,
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // FAIL, no match.
+ }
+
+ if (groupEndIdx == groupStartIdx) {
+ // The capture group match was of an empty string.
+ // Verified by testing: Perl matches succeed in this case, so
+ // we do too.
+ break;
+ }
+
+ UTEXT_SETNATIVEINDEX(fAltInputText, groupStartIdx);
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ UBool haveMatch = (opType == URX_BACKREF ?
+ (0 == utext_compareNativeLimit(fAltInputText, groupEndIdx, fInputText, -1)) :
+ (0 == utext_caseCompareNativeLimit(fAltInputText, groupEndIdx, fInputText, -1, U_FOLD_CASE_DEFAULT, &status)));
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+
+ if (fp->fInputIdx > fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // FAIL, no match.
+ } else if (!haveMatch) {
+ if (fp->fInputIdx == fActiveLimit) {
+ fHitEnd = TRUE;
+ }
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // FAIL, no match.
+ }
+ }
+ break;
+
+ case URX_STO_INP_LOC:
+ {
+ U_ASSERT(opValue >= 0 && opValue < fFrameSize);
+ fp->fExtra[opValue] = fp->fInputIdx;
+ }
+ break;
+
+ case URX_JMPX:
+ {
+ int32_t instrOperandLoc = (int32_t)fp->fPatIdx;
+ fp->fPatIdx += 1;
+ int32_t dataLoc = URX_VAL(pat[instrOperandLoc]);
+ U_ASSERT(dataLoc >= 0 && dataLoc < fFrameSize);
+ int64_t savedInputIdx = fp->fExtra[dataLoc];
+ U_ASSERT(savedInputIdx <= fp->fInputIdx);
+ if (savedInputIdx < fp->fInputIdx) {
+ fp->fPatIdx = opValue; // JMP
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // 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;
+ fActiveStart = fLookStart; // Set the match region change for
+ fActiveLimit = fLookLimit; // transparent bounds.
+ }
+ 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 =(int32_t)fData[opValue];
+ U_ASSERT(stackSize >= newStackSize);
+ if (stackSize > newStackSize) {
+ // Copy the current top frame back to the new (cut back) top frame.
+ // This makes the capture groups from within the look-ahead
+ // expression available.
+ int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
+ int32_t i;
+ for (i=0; i<fFrameSize; i++) {
+ newFP[i] = ((int64_t *)fp)[i];
+ }
+ fp = (REStackFrame *)newFP;
+ fStack->setSize(newStackSize);
+ }
+ fp->fInputIdx = fData[opValue+1];
+
+ // Restore the active region bounds in the input string; they may have
+ // been changed because of transparent bounds on a Region.
+ fActiveStart = fRegionStart;
+ fActiveLimit = fRegionLimit;
+ }
+ break;
+
+ case URX_ONECHAR_I:
+ if (fp->fInputIdx < fActiveLimit) {
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ break;
+ }
+ } else {
+ fHitEnd = TRUE;
+ }
+
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ UBool success = FALSE;
+ UChar32 c = UTEXT_PREVIOUS32(fInputText);
+ while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex) {
+ if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {
+ success = TRUE;
+ break;
+ } else if (c == U_SENTINEL) {
+ break;
+ }
+ c = UTEXT_PREVIOUS32(fInputText);
+ }
+ if (success) {
+ fHitEnd = FALSE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ 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.
+ const UCaseProps *csp = ucase_getSingleton();
+ {
+ int32_t stringStartIdx, stringLen;
+ stringStartIdx = opValue;
+
+ op = (int32_t)pat[fp->fPatIdx];
+ fp->fPatIdx++;
+ opType = URX_TYPE(op);
+ opValue = URX_VAL(op);
+ U_ASSERT(opType == URX_STRING_LEN);
+ stringLen = opValue;
+
+ const UChar *patternChars = litText+stringStartIdx;
+ const UChar *patternEnd = patternChars+stringLen;
+
+ const UChar *foldChars = NULL;
+ int32_t foldOffset, foldLength;
+ UChar32 c;
+
+ foldOffset = foldLength = 0;
+ UBool success = TRUE;
+
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ while (patternChars < patternEnd && success) {
+ if(foldOffset < foldLength) {
+ U16_NEXT_UNSAFE(foldChars, foldOffset, c);
+ } else {
+ c = UTEXT_NEXT32(fInputText);
+ if (c != U_SENTINEL) {
+ foldLength = ucase_toFullFolding(csp, c, &foldChars, U_FOLD_CASE_DEFAULT);
+ if(foldLength >= 0) {
+ if(foldLength <= UCASE_MAX_STRING_LENGTH) { // !!!: Does not correctly handle chars that fold to 0-length strings
+ foldOffset = 0;
+ U16_NEXT_UNSAFE(foldChars, foldOffset, c);
+ } else {
+ c = foldLength;
+ foldLength = foldOffset; // to avoid reading chars from the folding buffer
+ }
+ }
+ }
+
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+
+ success = FALSE;
+ if (c != U_SENTINEL && (fp->fInputIdx <= fActiveLimit)) {
+ if (U_IS_BMP(c)) {
+ success = (*patternChars == c);
+ patternChars += 1;
+ } else if (patternChars+1 < patternEnd) {
+ success = (*patternChars == U16_LEAD(c) && *(patternChars+1) == U16_TRAIL(c));
+ patternChars += 2;
+ }
+ } else {
+ fHitEnd = TRUE; // TODO: See ticket 6074
+ }
+ }
+
+ if (!success) {
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size()) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Reset to last start point
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ patternChars = litText+stringStartIdx;
+
+ // Search backwards for a possible start
+ do {
+ c = UTEXT_PREVIOUS32(fInputText);
+ if (c == U_SENTINEL) {
+ break;
+ } else {
+ foldLength = ucase_toFullFolding(csp, c, &foldChars, U_FOLD_CASE_DEFAULT);
+ if(foldLength >= 0) {
+ if(foldLength <= UCASE_MAX_STRING_LENGTH) { // !!!: Does not correctly handle chars that fold to 0-length strings
+ foldOffset = 0;
+ U16_NEXT_UNSAFE(foldChars, foldOffset, c);
+ } else {
+ c = foldLength;
+ foldLength = foldOffset; // to avoid reading chars from the folding buffer
+ }
+ }
+
+ if ((U_IS_BMP(c) && *patternChars == c) ||
+ (*patternChars == U16_LEAD(c) && *(patternChars+1) == U16_TRAIL(c))) {
+ success = TRUE;
+ break;
+ }
+ }
+ } while (UTEXT_GETNATIVEINDEX(fInputText) >= backSearchIndex);
+
+ // And try again
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ }
+ break;
+
+ case URX_LB_START:
+ {
+ // Entering a look-behind block.
+ // Save Stack Ptr, Input Pos.
+ // TODO: implement transparent bounds. Ticket #6067
+ 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] = fActiveLimit;
+ fActiveLimit = 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 = (int32_t)pat[fp->fPatIdx++];
+ int32_t maxML = (int32_t)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);
+ int64_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)--;
+ } else {
+ UTEXT_SETNATIVEINDEX(fInputText, *lbStartIdx);
+ (void)UTEXT_PREVIOUS32(fInputText);
+ *lbStartIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ }
+
+ 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(fFrameSize);
+ int64_t restoreInputLen = fData[opValue+3];
+ U_ASSERT(restoreInputLen >= fActiveLimit);
+ U_ASSERT(restoreInputLen <= fInputLength);
+ fActiveLimit = 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, 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 != fActiveLimit) {
+ // 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(fFrameSize);
+ 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.
+ int64_t originalInputLen = fData[opValue+3];
+ U_ASSERT(originalInputLen >= fActiveLimit);
+ U_ASSERT(originalInputLen <= fInputLength);
+ fActiveLimit = 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 = (int32_t)pat[fp->fPatIdx++];
+ int32_t maxML = (int32_t)pat[fp->fPatIdx++];
+ int32_t continueLoc = (int32_t)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);
+ int64_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)--;
+ } else {
+ UTEXT_SETNATIVEINDEX(fInputText, *lbStartIdx);
+ (void)UTEXT_PREVIOUS32(fInputText);
+ *lbStartIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ }
+
+ 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
+ int64_t restoreInputLen = fData[opValue+3];
+ U_ASSERT(restoreInputLen >= fActiveLimit);
+ U_ASSERT(restoreInputLen <= fInputLength);
+ fActiveLimit = 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, 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 != fActiveLimit) {
+ // 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(fFrameSize);
+ 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.
+ int64_t originalInputLen = fData[opValue+3];
+ U_ASSERT(originalInputLen >= fActiveLimit);
+ U_ASSERT(originalInputLen <= fInputLength);
+ fActiveLimit = 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 = (int32_t)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(fFrameSize);
+ }
+ 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.
+ int64_t ix = fp->fInputIdx;
+ UTEXT_SETNATIVEINDEX(fInputText, ix);
+ for (;;) {
+ if (ix >= fActiveLimit) {
+ fHitEnd = TRUE;
+ break;
+ }
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if (c<256) {
+ if (s8->contains(c) == FALSE) {
+ break;
+ }
+ } else {
+ if (s->contains(c) == FALSE) {
+ break;
+ }
+ }
+ ix = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+
+ // 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 = (int32_t)pat[fp->fPatIdx];
+ U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
+ int32_t stackLoc = URX_VAL(loopcOp);
+ U_ASSERT(stackLoc >= 0 && stackLoc < fFrameSize);
+ fp->fExtra[stackLoc] = fp->fInputIdx;
+ #ifdef REGEX_SMART_BACKTRACKING
+ backSearchIndex = fp->fInputIdx;
+ #endif
+ 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, 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 DOTALL mode, we can just go straight to the end of the input.
+ int64_t ix;
+ if ((opValue & 1) == 1) {
+ // Dot-matches-All mode. Jump straight to the end of the string.
+ ix = fActiveLimit;
+ fHitEnd = TRUE;
+ } else {
+ // NOT DOT ALL mode. Line endings do not match '.'
+ // Scan forward until a line ending or end of input.
+ ix = fp->fInputIdx;
+ UTEXT_SETNATIVEINDEX(fInputText, ix);
+ for (;;) {
+ if (ix >= fActiveLimit) {
+ fHitEnd = TRUE;
+ break;
+ }
+ UChar32 c = UTEXT_NEXT32(fInputText);
+ if ((c & 0x7f) <= 0x29) { // Fast filter of non-new-line-s
+ if ((c == 0x0a) || // 0x0a is newline in both modes.
+ (((opValue & 2) == 0) && // IF not UNIX_LINES mode
+ (c<=0x0d && c>=0x0a)) || c==0x85 ||c==0x2028 || c==0x2029) {
+ // char is a line ending. Exit the scanning loop.
+ break;
+ }
+ }
+ ix = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ }
+
+ // 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 .*
+ int32_t loopcOp = (int32_t)pat[fp->fPatIdx];
+ U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
+ int32_t stackLoc = URX_VAL(loopcOp);
+ U_ASSERT(stackLoc >= 0 && stackLoc < fFrameSize);
+ fp->fExtra[stackLoc] = fp->fInputIdx;
+ #ifdef REGEX_SMART_BACKTRACKING
+ backSearchIndex = fp->fInputIdx;
+ #endif
+ 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, status);
+ fp->fPatIdx++;
+ }
+ break;
+
+
+ case URX_LOOP_C:
+ {
+ U_ASSERT(opValue>=0 && opValue<fFrameSize);
+ backSearchIndex = fp->fExtra[opValue];
+ U_ASSERT(backSearchIndex <= fp->fInputIdx);
+ if (backSearchIndex == 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);
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ UChar32 prevC = UTEXT_PREVIOUS32(fInputText);
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+
+ UChar32 twoPrevC = UTEXT_PREVIOUS32(fInputText);
+ if (prevC == 0x0a &&
+ fp->fInputIdx > backSearchIndex &&
+ twoPrevC == 0x0d) {
+ int32_t prevOp = (int32_t)pat[fp->fPatIdx-2];
+ if (URX_TYPE(prevOp) == URX_LOOP_DOT_I) {
+ // .*, stepping back over CRLF pair.
+ fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
+ }
+ }
+
+
+ fp = StateSave(fp, fp->fPatIdx-1, status);
+ }
+ break;
+
+
+
+ default:
+ // Trouble. The compiled pattern contains an entry with an
+ // unrecognized type tag.
+ U_ASSERT(FALSE);
+ }
+
+ if (U_FAILURE(status)) {
+ isMatch = FALSE;
+ 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;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// MatchChunkAt This is the actual matching engine. Like MatchAt, but with the
+// assumption that the entire string is available in the UText's
+// chunk buffer. For now, that means we can use int32_t indexes,
+// except for anything that needs to be saved (like group starts
+// and ends).
+//
+// startIdx: begin matching a this index.
+// toEnd: if true, match must extend to end of the input region
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &status) {
+ UBool isMatch = FALSE; // True if the we have a match.
+
+ int32_t backSearchIndex = INT32_MAX; // used after greedy single-character matches for searching backwards
+
+ 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=%ld)\n", startIdx);
+ printf("Original Pattern: ");
+ UChar32 c = utext_next32From(fPattern->fPattern, 0);
+ while (c != U_SENTINEL) {
+ if (c<32 || c>256) {
+ c = '.';
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("%c", c));
+
+ c = UTEXT_NEXT32(fPattern->fPattern);
+ }
+ printf("\n");
+ printf("Input String: ");
+ c = utext_next32From(fInputText, 0);
+ while (c != U_SENTINEL) {
+ if (c<32 || c>256) {
+ c = '.';
+ }
+ printf("%c", c);
+
+ c = UTEXT_NEXT32(fInputText);
+ }
+ printf("\n");
+ printf("\n");
+ }
+#endif
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Cache frequently referenced items from the compiled pattern
+ //
+ int64_t *pat = fPattern->fCompiledPat->getBuffer();
+
+ const UChar *litText = fPattern->fLiteralText.getBuffer();
+ UVector *sets = fPattern->fSets;
+
+ const UChar *inputBuf = fInputText->chunkContents;
+
+ fFrameSize = fPattern->fFrameSize;
+ REStackFrame *fp = resetStack();
+
+ 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 = (int32_t)pat[fp->fPatIdx];
+ opType = URX_TYPE(op);
+ opValue = URX_VAL(op);
+#ifdef REGEX_RUN_DEBUG
+ if (fTraceDebug) {
+ UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
+ printf("inputIdx=%d inputChar=%x sp=%3d activeLimit=%d ", fp->fInputIdx,
+ UTEXT_CURRENT32(fInputText), (int64_t *)fp-fStack->getBuffer(), fActiveLimit);
+ 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(fFrameSize);
+ break;
+
+
+ case URX_ONECHAR:
+ if (fp->fInputIdx < fActiveLimit) {
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ if (c == opValue) {
+ break;
+ }
+ } else {
+ fHitEnd = TRUE;
+ }
+
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ int64_t reverseIndex = fp->fInputIdx;
+ UChar32 c;
+ do {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, c);
+ if (c == opValue) {
+ break;
+ }
+ } while (reverseIndex > backSearchIndex);
+ if (c == opValue) {
+ fHitEnd = FALSE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ 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 = (int32_t)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 > fActiveLimit) {
+ // No match. String is longer than the remaining input text.
+ fHitEnd = TRUE; // TODO: See ticket 6074
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ const UChar * pInp = inputBuf + fp->fInputIdx;
+ const UChar * pPat = litText+stringStartIdx;
+ const UChar * pEnd = pInp + stringLen;
+ UBool success = FALSE;
+ for(;;) {
+ if (*pInp == *pPat) {
+ pInp++;
+ pPat++;
+ if (pInp == pEnd) {
+ // Successful Match.
+ success = TRUE;
+ break;
+ }
+ } else {
+ // Match failed.
+ break;
+ }
+ }
+
+ if (success) {
+ fp->fInputIdx += stringLen;
+ } else {
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size()) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Reset to last start point
+ int64_t reverseIndex = fp->fInputIdx;
+ UChar32 c;
+ pPat = litText+stringStartIdx;
+
+ // Search backwards for a possible start
+ do {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, c);
+ if ((U_IS_BMP(c) && *pPat == c) ||
+ (*pPat == U16_LEAD(c) && *(pPat+1) == U16_TRAIL(c))) {
+ success = TRUE;
+ break;
+ }
+ } while (reverseIndex > backSearchIndex);
+
+ // And try again
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_STATE_SAVE:
+ fp = StateSave(fp, opValue, 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.
+ if (toEnd && fp->fInputIdx != fActiveLimit) {
+ // The pattern matched, but not to the end of input. Try some more.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+ isMatch = TRUE;
+ goto breakFromLoop;
+
+ // Start and End Capture stack frame variables are laid out 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 < fFrameSize-3);
+ fp->fExtra[opValue+2] = fp->fInputIdx;
+ break;
+
+
+ case URX_END_CAPTURE:
+ U_ASSERT(opValue >= 0 && opValue < fFrameSize-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 < fAnchorLimit-2) {
+ // We are no where near the end of input. Fail.
+ // This is the common case. Keep it first.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+ if (fp->fInputIdx >= fAnchorLimit) {
+ // We really are at the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+
+ // If we are positioned just before a new-line that is located at the
+ // end of input, succeed.
+ if (fp->fInputIdx == fAnchorLimit-1) {
+ UChar32 c;
+ U16_GET(inputBuf, fAnchorStart, fp->fInputIdx, fAnchorLimit, c);
+
+ if ((c>=0x0a && c<=0x0d) || c==0x85 || c==0x2028 || c==0x2029) {
+ if ( !(c==0x0a && fp->fInputIdx>fAnchorStart && inputBuf[fp->fInputIdx-1]==0x0d)) {
+ // At new-line at end of input. Success
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+ }
+ } else if (fp->fInputIdx == fAnchorLimit-2 &&
+ inputBuf[fp->fInputIdx]==0x0d && inputBuf[fp->fInputIdx+1]==0x0a) {
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break; // At CR/LF at end of input. Success
+ }
+
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+
+ break;
+
+
+ case URX_DOLLAR_D: // $, test for End of Line, in UNIX_LINES mode.
+ if (fp->fInputIdx >= fAnchorLimit-1) {
+ // Either at the last character of input, or off the end.
+ if (fp->fInputIdx == fAnchorLimit-1) {
+ // At last char of input. Success if it's a new line.
+ if (inputBuf[fp->fInputIdx] == 0x0a) {
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+ } else {
+ // Off the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ break;
+ }
+ }
+
+ // Not at end of input. Back-track out.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+
+
+ case URX_DOLLAR_M: // $, test for End of line in multi-line mode
+ {
+ if (fp->fInputIdx >= fAnchorLimit) {
+ // We really are at the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ 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>=0x0a && c<=0x0d) || 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
+ // In multi-line mode, hitting a new-line just before the end of input does not
+ // set the hitEnd or requireEnd flags
+ if ( !(c==0x0a && fp->fInputIdx>fAnchorStart && inputBuf[fp->fInputIdx-1]==0x0d)) {
+ break;
+ }
+ }
+ // not at a new line. Fail.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_DOLLAR_MD: // $, test for End of line in multi-line and UNIX_LINES mode
+ {
+ if (fp->fInputIdx >= fAnchorLimit) {
+ // We really are at the end of input. Success.
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE; // Java set requireEnd in this case, even though
+ break; // adding a new-line would not lose the match.
+ }
+ // If we are not positioned just before a new-line, the test fails; backtrack out.
+ // It makes no difference where the new-line is within the input.
+ if (inputBuf[fp->fInputIdx] != 0x0a) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_CARET: // ^, test for start of line
+ if (fp->fInputIdx != fAnchorStart) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_CARET_M: // ^, test for start of line in mulit-line mode
+ {
+ if (fp->fInputIdx == fAnchorStart) {
+ // 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 < fAnchorLimit) &&
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ // It's a new-line. ^ is true. Success.
+ // TODO: what should be done with positions between a CR and LF?
+ break;
+ }
+ // Not at the start of a line. Fail.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_CARET_M_UNIX: // ^, test for start of line in mulit-line + Unix-line mode
+ {
+ U_ASSERT(fp->fInputIdx >= fAnchorStart);
+ if (fp->fInputIdx <= fAnchorStart) {
+ // We are at the start input. Success.
+ break;
+ }
+ // Check whether character just before the current pos is a new-line
+ U_ASSERT(fp->fInputIdx <= fAnchorLimit);
+ UChar c = inputBuf[fp->fInputIdx - 1];
+ if (c != 0x0a) {
+ // Not at the start of a line. Back-track out.
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+ case URX_BACKSLASH_B: // Test for word boundaries
+ {
+ UBool success = isChunkWordBoundary((int32_t)fp->fInputIdx);
+ success ^= (opValue != 0); // flip sense for \B
+ if (!success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ 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(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_BACKSLASH_D: // Test for decimal digit
+ {
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ int8_t ctype = u_charType(c); // TODO: make a unicode set for this. Will be faster.
+ UBool success = (ctype == U_DECIMAL_DIGIT_NUMBER);
+ success ^= (opValue != 0); // flip sense for \D
+ if (!success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+
+ case URX_BACKSLASH_G: // Test for position at end of previous match
+ if (!((fMatch && fp->fInputIdx==fMatchEnd) || (fMatch==FALSE && fp->fInputIdx==fActiveStart))) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ 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 >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ // Examine (and consume) the current char.
+ // Dispatch into a little state machine, based on the char.
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, 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 >= fActiveLimit) goto GC_Done;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, 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 >= fActiveLimit) goto GC_Done;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, 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 >= fActiveLimit) goto GC_Done;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, 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 >= fActiveLimit) {
+ break;
+ }
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ if (sets[URX_GC_EXTEND]->contains(c) == FALSE) {
+ U16_BACK_1(inputBuf, 0, fp->fInputIdx);
+ break;
+ }
+ }
+ 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 < fActiveLimit && inputBuf[fp->fInputIdx] == 0x0a) {
+ fp->fInputIdx++;
+ }
+
+GC_Done:
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ }
+ break;
+ }
+
+
+
+
+ case URX_BACKSLASH_Z: // Test for end of Input
+ if (fp->fInputIdx < fAnchorLimit) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ } else {
+ fHitEnd = TRUE;
+ fRequireEnd = TRUE;
+ }
+ 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 >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ 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, fActiveLimit, 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) {
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Try to find it, backwards
+ int64_t reverseIndex = fp->fInputIdx;
+ U16_BACK_1(inputBuf, backSearchIndex, reverseIndex); // skip the first character we tried
+ success = ((opValue & URX_NEG_SET) == URX_NEG_SET); // reset
+ do {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, 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;
+ }
+ }
+ } while (reverseIndex > backSearchIndex && !success);
+
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ 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 >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
+
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, 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;
+ }
+ }
+
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Try to find it, backwards
+ int64_t reverseIndex = fp->fInputIdx;
+ U16_BACK_1(inputBuf, backSearchIndex, reverseIndex); // skip the first character we tried
+ UBool success = FALSE;
+ do {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, c);
+ if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
+ if (s8->contains(c) == FALSE) {
+ success = TRUE;
+ break;
+ }
+ } else {
+ const UnicodeSet *s = fPattern->fStaticSets[opValue];
+ if (s->contains(c) == FALSE) {
+ success = TRUE;
+ break;
+ }
+ }
+ } while (reverseIndex > backSearchIndex);
+
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_SETREF:
+ {
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ U_ASSERT(opValue > 0 && opValue < sets->size());
+
+ // There is input left. Pick up one char and test it for set membership.
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ if (c<256) {
+ Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+ if (s8->contains(c)) {
+ // The character is in the set. A Match.
+ break;
+ }
+ } else {
+ UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ if (s->contains(c)) {
+ // The character is in the set. A Match.
+ break;
+ }
+ }
+
+ // the character wasn't in the set.
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Try to find it, backwards
+ int64_t reverseIndex = fp->fInputIdx;
+ U16_BACK_1(inputBuf, backSearchIndex, reverseIndex); // skip the first character we tried
+ UBool success = FALSE;
+ do {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, c);
+ if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+ if (s8->contains(c)) {
+ success = TRUE;
+ break;
+ }
+ } else {
+ UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ if (s->contains(c)) {
+ success = TRUE;
+ break;
+ }
+ }
+ } while (reverseIndex > backSearchIndex);
+
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > reverseIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ break;
+
+
+ case URX_DOTANY:
+ {
+ // . matches anything, but stops at end-of-line.
+ if (fp->fInputIdx >= fActiveLimit) {
+ // At end of input. Match failed. Backtrack out.
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ // There is input left. Advance over one char, unless we've hit end-of-line
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, 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(fFrameSize);
+ break;
+ }
+ }
+ break;
+
+
+ case URX_DOTANY_ALL:
+ {
+ // . in dot-matches-all (including new lines) mode
+ if (fp->fInputIdx >= fActiveLimit) {
+ // At end of input. Match failed. Backtrack out.
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ 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, fActiveLimit, c);
+ if (c==0x0d && fp->fInputIdx < fActiveLimit) {
+ // In the case of a CR/LF, we need to advance over both.
+ if (inputBuf[fp->fInputIdx] == 0x0a) {
+ U16_FWD_1(inputBuf, fp->fInputIdx, fActiveLimit);
+ }
+ }
+ }
+ break;
+
+
+ case URX_DOTANY_UNIX:
+ {
+ // '.' operator, matches all, but stops at end-of-line.
+ // UNIX_LINES mode, so 0x0a is the only recognized line ending.
+ if (fp->fInputIdx >= fActiveLimit) {
+ // At end of input. Match failed. Backtrack out.
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ break;
+ }
+
+ // There is input left. Advance over one char, unless we've hit end-of-line
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ if (c == 0x0a) {
+ // End of line in normal mode. '.' does not match the \n
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ 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, 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 = (int32_t)pat[opValue-1];
+ U_ASSERT(URX_TYPE(stoOp) == URX_STO_INP_LOC);
+ int32_t frameLoc = URX_VAL(stoOp);
+ U_ASSERT(frameLoc >= 0 && frameLoc < fFrameSize);
+ int32_t prevInputIdx = (int32_t)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, 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 < fFrameSize-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 = (int32_t)fp->fPatIdx;
+ fp->fPatIdx += 3;
+ int32_t loopLoc = URX_VAL(pat[instrOperandLoc]);
+ int32_t minCount = (int32_t)pat[instrOperandLoc+1];
+ int32_t maxCount = (int32_t)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, status);
+ }
+ if (maxCount == 0) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ break;
+
+ case URX_CTR_LOOP:
+ {
+ U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
+ int32_t initOp = (int32_t)pat[opValue];
+ U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT);
+ int64_t *pCounter = &fp->fExtra[URX_VAL(initOp)];
+ int32_t minCount = (int32_t)pat[opValue+2];
+ int32_t maxCount = (int32_t)pat[opValue+3];
+ // Increment the counter. Note: we DIDN'T worry about counter
+ // overflow, since the data comes from UnicodeStrings, which
+ // stores its length in an int32_t. Do we have to think about
+ // this now that we're using UText? Probably not, since the length
+ // in UChar32s is still an int32_t.
+ (*pCounter)++;
+ U_ASSERT(*pCounter > 0);
+ if ((uint64_t)*pCounter >= (uint32_t)maxCount) {
+ U_ASSERT(*pCounter == maxCount || maxCount == -1);
+ break;
+ }
+ if (*pCounter >= minCount) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx = opValue + 4; // Loop back.
+ }
+ break;
+
+ case URX_CTR_INIT_NG:
+ {
+ // Initialize a non-greedy loop
+ U_ASSERT(opValue >= 0 && opValue < fFrameSize-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 = (int32_t)fp->fPatIdx;
+ fp->fPatIdx += 3;
+ int32_t loopLoc = URX_VAL(pat[instrOperandLoc]);
+ int32_t minCount = (int32_t)pat[instrOperandLoc+1];
+ int32_t maxCount = (int32_t)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, status);
+ }
+ fp->fPatIdx = loopLoc+1; // Continue with stuff after repeated block
+ }
+ }
+ break;
+
+ case URX_CTR_LOOP_NG:
+ {
+ // Non-greedy {min, max} loops
+ U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
+ int32_t initOp = (int32_t)pat[opValue];
+ U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT_NG);
+ int64_t *pCounter = &fp->fExtra[URX_VAL(initOp)];
+ int32_t minCount = (int32_t)pat[opValue+2];
+ int32_t maxCount = (int32_t)pat[opValue+3];
+ // Increment the counter. Note: we DIDN'T worry about counter
+ // overflow, since the data comes from UnicodeStrings, which
+ // stores its length in an int32_t. Do we have to think about
+ // this now that we're using UText? Probably not, since the length
+ // in UChar32s is still an int32_t.
+ (*pCounter)++;
+ U_ASSERT(*pCounter > 0);
+
+ if ((uint64_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, status);
+ }
+ }
+ break;
+
+ 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 = (int32_t)fData[opValue];
+ U_ASSERT(newStackSize <= fStack->size());
+ int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
+ if (newFP == (int64_t *)fp) {
+ break;
+ }
+ int32_t i;
+ for (i=0; i<fFrameSize; i++) {
+ newFP[i] = ((int64_t *)fp)[i];
+ }
+ fp = (REStackFrame *)newFP;
+ fStack->setSize(newStackSize);
+ }
+ break;
+
+ case URX_BACKREF:
+ case URX_BACKREF_I:
+ {
+ U_ASSERT(opValue < fFrameSize);
+ int64_t groupStartIdx = fp->fExtra[opValue];
+ int64_t groupEndIdx = fp->fExtra[opValue+1];
+ U_ASSERT(groupStartIdx <= groupEndIdx);
+ int64_t len = groupEndIdx-groupStartIdx;
+ if (groupStartIdx < 0) {
+ // This capture group has not participated in the match thus far,
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // 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 <= fActiveLimit) {
+ if (opType == URX_BACKREF) {
+ if (u_strncmp(inputBuf+groupStartIdx, inputBuf+fp->fInputIdx, (int32_t)len) == 0) {
+ haveMatch = TRUE;
+ }
+ } else {
+ if (u_strncasecmp(inputBuf+groupStartIdx, inputBuf+fp->fInputIdx,
+ (int32_t)len, U_FOLD_CASE_DEFAULT) == 0) {
+ haveMatch = TRUE;
+ }
+ }
+ } else {
+ // TODO: probably need to do a partial string comparison, and only
+ // set HitEnd if the available input matched. Ticket #6074
+ fHitEnd = TRUE;
+ }
+ if (haveMatch) {
+ fp->fInputIdx += len; // Match. Advance current input position.
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // FAIL, no match.
+ }
+ }
+ break;
+
+ case URX_STO_INP_LOC:
+ {
+ U_ASSERT(opValue >= 0 && opValue < fFrameSize);
+ fp->fExtra[opValue] = fp->fInputIdx;
+ }
+ break;
+
+ case URX_JMPX:
+ {
+ int32_t instrOperandLoc = (int32_t)fp->fPatIdx;
+ fp->fPatIdx += 1;
+ int32_t dataLoc = URX_VAL(pat[instrOperandLoc]);
+ U_ASSERT(dataLoc >= 0 && dataLoc < fFrameSize);
+ int32_t savedInputIdx = (int32_t)fp->fExtra[dataLoc];
+ U_ASSERT(savedInputIdx <= fp->fInputIdx);
+ if (savedInputIdx < fp->fInputIdx) {
+ fp->fPatIdx = opValue; // JMP
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize); // 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;
+ fActiveStart = fLookStart; // Set the match region change for
+ fActiveLimit = fLookLimit; // transparent bounds.
+ }
+ 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 = (int32_t)fData[opValue];
+ U_ASSERT(stackSize >= newStackSize);
+ if (stackSize > newStackSize) {
+ // Copy the current top frame back to the new (cut back) top frame.
+ // This makes the capture groups from within the look-ahead
+ // expression available.
+ int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
+ int32_t i;
+ for (i=0; i<fFrameSize; i++) {
+ newFP[i] = ((int64_t *)fp)[i];
+ }
+ fp = (REStackFrame *)newFP;
+ fStack->setSize(newStackSize);
+ }
+ fp->fInputIdx = fData[opValue+1];
+
+ // Restore the active region bounds in the input string; they may have
+ // been changed because of transparent bounds on a Region.
+ fActiveStart = fRegionStart;
+ fActiveLimit = fRegionLimit;
+ }
+ break;
+
+ case URX_ONECHAR_I:
+ if (fp->fInputIdx < fActiveLimit) {
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {
+ break;
+ }
+ } else {
+ fHitEnd = TRUE;
+ }
+
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size() > fFrameSize) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ UBool success = FALSE;
+ int64_t reverseIndex = fp->fInputIdx;
+ UChar32 c;
+ while (reverseIndex > backSearchIndex) {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, c);
+ if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {
+ success = TRUE;
+ break;
+ } else if (c == U_SENTINEL) {
+ break;
+ }
+ }
+ if (success) {
+ fHitEnd = FALSE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ 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.
+ const UCaseProps *csp = ucase_getSingleton();
+ {
+ int32_t stringStartIdx, stringLen;
+ stringStartIdx = opValue;
+
+ op = (int32_t)pat[fp->fPatIdx];
+ fp->fPatIdx++;
+ opType = URX_TYPE(op);
+ opValue = URX_VAL(op);
+ U_ASSERT(opType == URX_STRING_LEN);
+ stringLen = opValue;
+
+ const UChar *patternChars = litText+stringStartIdx;
+ const UChar *patternEnd = patternChars+stringLen;
+
+ const UChar *foldChars = NULL;
+ int32_t foldOffset, foldLength;
+ UChar32 c;
+
+ #ifdef REGEX_SMART_BACKTRACKING
+ int32_t originalInputIdx = fp->fInputIdx;
+ #endif
+ UBool success = TRUE;
+
+ foldOffset = foldLength = 0;
+
+ while (patternChars < patternEnd && success) {
+ if(foldOffset < foldLength) {
+ U16_NEXT_UNSAFE(foldChars, foldOffset, c);
+ } else {
+ U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+ foldLength = ucase_toFullFolding(csp, c, &foldChars, U_FOLD_CASE_DEFAULT);
+ if(foldLength >= 0) {
+ if(foldLength <= UCASE_MAX_STRING_LENGTH) { // !!!: Does not correctly handle chars that fold to 0-length strings
+ foldOffset = 0;
+ U16_NEXT_UNSAFE(foldChars, foldOffset, c);
+ } else {
+ c = foldLength;
+ foldLength = foldOffset; // to avoid reading chars from the folding buffer
+ }
+ }
+ }
+
+ if (fp->fInputIdx <= fActiveLimit) {
+ if (U_IS_BMP(c)) {
+ success = (*patternChars == c);
+ patternChars += 1;
+ } else if (patternChars+1 < patternEnd) {
+ success = (*patternChars == U16_LEAD(c) && *(patternChars+1) == U16_TRAIL(c));
+ patternChars += 2;
+ }
+ } else {
+ success = FALSE;
+ fHitEnd = TRUE; // TODO: See ticket 6074
+ }
+ }
+
+ if (!success) {
+ #ifdef REGEX_SMART_BACKTRACKING
+ if (fp->fInputIdx > backSearchIndex && fStack->size()) {
+ REStackFrame *prevFrame = (REStackFrame *)fStack->peekFrame(fFrameSize);
+ if (URX_LOOP_C == URX_TYPE(pat[prevFrame->fPatIdx]) && fp->fInputIdx <= prevFrame->fInputIdx) {
+ // Reset to last start point
+ int64_t reverseIndex = originalInputIdx;
+ patternChars = litText+stringStartIdx;
+
+ // Search backwards for a possible start
+ do {
+ U16_PREV(inputBuf, backSearchIndex, reverseIndex, c);
+ foldLength = ucase_toFullFolding(csp, c, &foldChars, U_FOLD_CASE_DEFAULT);
+ if(foldLength >= 0) {
+ if(foldLength <= UCASE_MAX_STRING_LENGTH) { // !!!: Does not correctly handle chars that fold to 0-length strings
+ foldOffset = 0;
+ U16_NEXT_UNSAFE(foldChars, foldOffset, c);
+ } else {
+ c = foldLength;
+ foldLength = foldOffset; // to avoid reading chars from the folding buffer
+ }
+ }
+
+ if ((U_IS_BMP(c) && *patternChars == c) ||
+ (*patternChars == U16_LEAD(c) && *(patternChars+1) == U16_TRAIL(c))) {
+ success = TRUE;
+ break;
+ }
+ } while (reverseIndex > backSearchIndex);
+
+ // And try again
+ if (success) {
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ fp->fInputIdx = reverseIndex;
+ if (fp->fInputIdx > backSearchIndex) {
+ fp = StateSave(fp, fp->fPatIdx, status);
+ }
+ fp->fPatIdx++; // Skip the LOOP_C, we just did that
+ break;
+ }
+ }
+ }
+ #endif
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ }
+ }
+ }
+ break;
+
+ case URX_LB_START:
+ {
+ // Entering a look-behind block.
+ // Save Stack Ptr, Input Pos.
+ // TODO: implement transparent bounds. Ticket #6067
+ 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] = fActiveLimit;
+ fActiveLimit = 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 = (int32_t)pat[fp->fPatIdx++];
+ int32_t maxML = (int32_t)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);
+ int64_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)--;
+ } 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(fFrameSize);
+ int64_t restoreInputLen = fData[opValue+3];
+ U_ASSERT(restoreInputLen >= fActiveLimit);
+ U_ASSERT(restoreInputLen <= fInputLength);
+ fActiveLimit = 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, 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 != fActiveLimit) {
+ // 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(fFrameSize);
+ 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.
+ int64_t originalInputLen = fData[opValue+3];
+ U_ASSERT(originalInputLen >= fActiveLimit);
+ U_ASSERT(originalInputLen <= fInputLength);
+ fActiveLimit = 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 = (int32_t)pat[fp->fPatIdx++];
+ int32_t maxML = (int32_t)pat[fp->fPatIdx++];
+ int32_t continueLoc = (int32_t)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);
+ int64_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
+ int64_t restoreInputLen = fData[opValue+3];
+ U_ASSERT(restoreInputLen >= fActiveLimit);
+ U_ASSERT(restoreInputLen <= fInputLength);
+ fActiveLimit = 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, 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 != fActiveLimit) {
+ // 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(fFrameSize);
+ 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.
+ int64_t originalInputLen = fData[opValue+3];
+ U_ASSERT(originalInputLen >= fActiveLimit);
+ U_ASSERT(originalInputLen <= fInputLength);
+ fActiveLimit = 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 = (int32_t)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(fFrameSize);
+ }
+ 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 = (int32_t)fp->fInputIdx;
+ for (;;) {
+ if (ix >= fActiveLimit) {
+ fHitEnd = TRUE;
+ break;
+ }
+ UChar32 c;
+ U16_NEXT(inputBuf, ix, fActiveLimit, 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 = (int32_t)pat[fp->fPatIdx];
+ U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
+ int32_t stackLoc = URX_VAL(loopcOp);
+ U_ASSERT(stackLoc >= 0 && stackLoc < fFrameSize);
+ fp->fExtra[stackLoc] = fp->fInputIdx;
+ #ifdef REGEX_SMART_BACKTRACKING
+ backSearchIndex = fp->fInputIdx;
+ #endif
+ 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, 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 DOTALL mode, we can just go straight to the end of the input.
+ int32_t ix;
+ if ((opValue & 1) == 1) {
+ // Dot-matches-All mode. Jump straight to the end of the string.
+ ix = (int32_t)fActiveLimit;
+ fHitEnd = TRUE;
+ } else {
+ // NOT DOT ALL mode. Line endings do not match '.'
+ // Scan forward until a line ending or end of input.
+ ix = (int32_t)fp->fInputIdx;
+ for (;;) {
+ if (ix >= fActiveLimit) {
+ fHitEnd = TRUE;
+ break;
+ }
+ UChar32 c;
+ U16_NEXT(inputBuf, ix, fActiveLimit, c); // c = inputBuf[ix++]
+ if ((c & 0x7f) <= 0x29) { // Fast filter of non-new-line-s
+ if ((c == 0x0a) || // 0x0a is newline in both modes.
+ (((opValue & 2) == 0) && // IF not UNIX_LINES mode
+ ((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 .*
+ int32_t loopcOp = (int32_t)pat[fp->fPatIdx];
+ U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
+ int32_t stackLoc = URX_VAL(loopcOp);
+ U_ASSERT(stackLoc >= 0 && stackLoc < fFrameSize);
+ fp->fExtra[stackLoc] = fp->fInputIdx;
+ #ifdef REGEX_SMART_BACKTRACKING
+ backSearchIndex = fp->fInputIdx;
+ #endif
+ 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, status);
+ fp->fPatIdx++;
+ }
+ break;
+
+
+ case URX_LOOP_C:
+ {
+ U_ASSERT(opValue>=0 && opValue<fFrameSize);
+ backSearchIndex = (int32_t)fp->fExtra[opValue];
+ U_ASSERT(backSearchIndex <= fp->fInputIdx);
+ if (backSearchIndex == 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);
+ UChar32 prevC;
+ U16_PREV(inputBuf, 0, fp->fInputIdx, prevC); // !!!: should this 0 be one of f*Limit?
+
+ if (prevC == 0x0a &&
+ fp->fInputIdx > backSearchIndex &&
+ inputBuf[fp->fInputIdx-1] == 0x0d) {
+ int32_t prevOp = (int32_t)pat[fp->fPatIdx-2];
+ if (URX_TYPE(prevOp) == URX_LOOP_DOT_I) {
+ // .*, stepping back over CRLF pair.
+ U16_BACK_1(inputBuf, 0, fp->fInputIdx);
+ }
+ }
+
+
+ fp = StateSave(fp, fp->fPatIdx-1, status);
+ }
+ break;
+
+
+
+ default:
+ // Trouble. The compiled pattern contains an entry with an
+ // unrecognized type tag.
+ U_ASSERT(FALSE);
+ }
+
+ if (U_FAILURE(status)) {
+ isMatch = FALSE;
+ 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-4.8.1/i18n/remtrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/remtrans.cpp
new file mode 100644
index 00000000000..c21c79b4f94
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/remtrans.cpp
@@ -0,0 +1,68 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2008, 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 (result != NULL && 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-4.8.1/i18n/remtrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/remtrans.h
new file mode 100644
index 00000000000..25a5609dffe
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/repattrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/repattrn.cpp
new file mode 100644
index 00000000000..64971a6d4c8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/repattrn.cpp
@@ -0,0 +1,817 @@
+//
+// file: repattrn.cpp
+//
+/*
+***************************************************************************
+* Copyright (C) 2002-2011 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 "uvectr64.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();
+}
+
+
+//--------------------------------------------------------------------------
+//
+// 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;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// Assignment 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
+ if ( other.fPatternString == NULL ) {
+ fPatternString = NULL;
+ fPattern = utext_clone(fPattern, other.fPattern, FALSE, TRUE, &fDeferredStatus);
+ } else {
+ fPatternString = new UnicodeString(*(other.fPatternString));
+ UErrorCode status = U_ZERO_ERROR;
+ fPattern = utext_openConstUnicodeString(NULL, fPatternString, &status);
+ if (U_FAILURE(status)) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
+ }
+ 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;
+ fNeedsAltInput = other.fNeedsAltInput;
+
+ // 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];
+ if (fSets8 == NULL) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
+ 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() {
+ 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;
+ fNeedsAltInput = FALSE;
+
+ fPattern = NULL; // will be set later
+ fPatternString = NULL; // may be set later
+ fCompiledPat = new UVector64(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;
+ if (fPattern != NULL) {
+ utext_close(fPattern);
+ fPattern = NULL;
+ }
+ if (fPatternString != NULL) {
+ delete fPatternString;
+ fPatternString = 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.
+// Note that pattern strings with the same
+// characters can still be considered different.
+//
+//--------------------------------------------------------------------------
+UBool RegexPattern::operator ==(const RegexPattern &other) const {
+ if (this->fFlags == other.fFlags && this->fDeferredStatus == other.fDeferredStatus) {
+ if (this->fPatternString != NULL && other.fPatternString != NULL) {
+ return *(this->fPatternString) == *(other.fPatternString);
+ } else if (this->fPattern == NULL) {
+ if (other.fPattern == NULL) {
+ return TRUE;
+ }
+ } else if (other.fPattern != NULL) {
+ UTEXT_SETNATIVEINDEX(this->fPattern, 0);
+ UTEXT_SETNATIVEINDEX(other.fPattern, 0);
+ return utext_equals(this->fPattern, other.fPattern);
+ }
+ }
+ return FALSE;
+}
+
+//---------------------------------------------------------------------
+//
+// 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 |
+ UREGEX_ERROR_ON_UNKNOWN_ESCAPES | UREGEX_UNIX_LINES | UREGEX_LITERAL;
+
+ if ((flags & ~allFlags) != 0) {
+ status = U_REGEX_INVALID_FLAG;
+ return NULL;
+ }
+
+ if ((flags & (UREGEX_CANON_EQ | UREGEX_LITERAL)) != 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;
+ delete This;
+ return NULL;
+ }
+ This->fFlags = flags;
+
+ RegexCompile compiler(This, status);
+ compiler.compile(regex, pe, status);
+
+ if (U_FAILURE(status)) {
+ delete This;
+ This = NULL;
+ }
+
+ return This;
+}
+
+
+//
+// compile, UText mode
+//
+RegexPattern * U_EXPORT2
+RegexPattern::compile(UText *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 |
+ UREGEX_ERROR_ON_UNKNOWN_ESCAPES | UREGEX_UNIX_LINES | UREGEX_LITERAL;
+
+ if ((flags & ~allFlags) != 0) {
+ status = U_REGEX_INVALID_FLAG;
+ return NULL;
+ }
+
+ if ((flags & (UREGEX_CANON_EQ | UREGEX_LITERAL)) != 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;
+ delete This;
+ return NULL;
+ }
+ This->fFlags = flags;
+
+ RegexCompile compiler(This, status);
+ compiler.compile(regex, pe, status);
+
+ if (U_FAILURE(status)) {
+ delete This;
+ This = NULL;
+ }
+
+ 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 default flags, UText mode
+//
+RegexPattern * U_EXPORT2
+RegexPattern::compile(UText *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);
+}
+
+
+//
+// compile with no UParseErr parameter, UText mode
+//
+RegexPattern * U_EXPORT2
+RegexPattern::compile(UText *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->fDeferredStatus = status;
+ retMatcher->reset(input);
+ }
+ return retMatcher;
+}
+
+
+//---------------------------------------------------------------------
+//
+// 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;
+}
+
+
+//
+// matches, UText mode
+//
+UBool U_EXPORT2 RegexPattern::matches(UText *regex,
+ UText *input,
+ UParseError &pe,
+ UErrorCode &status) {
+
+ if (U_FAILURE(status)) {return FALSE;}
+
+ UBool retVal = FALSE;
+ RegexPattern *pat = NULL;
+ RegexMatcher *matcher = NULL;
+
+ pat = RegexPattern::compile(regex, 0, pe, status);
+ matcher = pat->matcher(status);
+ if (U_SUCCESS(status)) {
+ matcher->reset(input);
+ retVal = matcher->matches(status);
+ }
+
+ delete matcher;
+ delete pat;
+ return retVal;
+}
+
+
+
+
+
+//---------------------------------------------------------------------
+//
+// pattern
+//
+//---------------------------------------------------------------------
+UnicodeString RegexPattern::pattern() const {
+ if (fPatternString != NULL) {
+ return *fPatternString;
+ } else if (fPattern == NULL) {
+ return UnicodeString();
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ int64_t nativeLen = utext_nativeLength(fPattern);
+ int32_t len16 = utext_extract(fPattern, 0, nativeLen, NULL, 0, &status); // buffer overflow error
+ UnicodeString result;
+
+ status = U_ZERO_ERROR;
+ UChar *resultChars = result.getBuffer(len16);
+ utext_extract(fPattern, 0, nativeLen, resultChars, len16, &status); // unterminated warning
+ result.releaseBuffer(len16);
+
+ return result;
+ }
+}
+
+
+
+
+//---------------------------------------------------------------------
+//
+// patternText
+//
+//---------------------------------------------------------------------
+UText *RegexPattern::patternText(UErrorCode &status) const {
+ if (U_FAILURE(status)) {return NULL;}
+ status = U_ZERO_ERROR;
+
+ if (fPattern != NULL) {
+ return fPattern;
+ } else {
+ RegexStaticSets::initGlobals(&status);
+ return RegexStaticSets::gStaticSets->fEmptyText;
+ }
+}
+
+
+
+//---------------------------------------------------------------------
+//
+// 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 = 0;
+ // Check m's status to make sure all is ok.
+ if (U_SUCCESS(m.fDeferredStatus)) {
+ r = m.split(input, dest, destCapacity, status);
+ }
+ return r;
+}
+
+//
+// split, UText mode
+//
+int32_t RegexPattern::split(UText *input,
+ UText *dest[],
+ int32_t destCapacity,
+ UErrorCode &status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ };
+
+ RegexMatcher m(this);
+ int32_t r = 0;
+ // Check m's status to make sure all is ok.
+ if (U_SUCCESS(m.fDeferredStatus)) {
+ 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 ((uint32_t)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_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: "));
+ UChar32 c = utext_next32From(This->fPattern, 0);
+ while (c != U_SENTINEL) {
+ if (c<32 || c>256) {
+ c = '.';
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("%c", c));
+
+ c = UTEXT_NEXT32(This->fPattern);
+ }
+ 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 string: \""));
+ for (i=This->fInitialStringIdx; i<This->fInitialStringIdx+This->fInitialStringLen; i++) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c", This->fLiteralText[i])); // TODO: non-printables, surrogates.
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("\"\n"));
+
+ } 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-4.8.1/i18n/search.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/search.cpp
new file mode 100644
index 00000000000..5d2aa139415
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/search.cpp
@@ -0,0 +1,443 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2008,2010 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 03/22/2000 helena Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#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_->elementComparisonType = other.m_search_->elementComparisonType;
+ 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;
+ case USEARCH_ELEMENT_COMPARISON :
+ if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
+ m_search_->elementComparisonType = (int16_t)value;
+ } else {
+ m_search_->elementComparisonType = 0;
+ }
+ 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);
+ case USEARCH_ELEMENT_COMPARISON :
+ {
+ int16_t value = m_search_->elementComparisonType;
+ if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
+ return (USearchAttributeValue)value;
+ } else {
+ return USEARCH_STANDARD_ELEMENT_COMPARISON;
+ }
+ }
+ 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)) {
+#if 0
+ m_search_->breakIter = NULL;
+ // the c++ breakiterator may not make use of ubreakiterator.
+ // so we'll have to keep track of it ourselves.
+#else
+ // Well, gee... the Constructors that take a BreakIterator
+ // all cast the BreakIterator to a UBreakIterator and
+ // pass it to the corresponding usearch_openFromXXX
+ // routine, so there's no reason not to do this.
+ //
+ // Besides, a UBreakIterator is a BreakIterator, so
+ // any subclass of BreakIterator should work fine here...
+ m_search_->breakIter = (UBreakIterator *) breakiter;
+#endif
+
+ 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_->elementComparisonType == that.m_search_->elementComparisonType &&
+ 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) {
+ if (m_search_->isOverlap) {
+ matchindex += m_search_->matchedLength - 2;
+ }
+
+ 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_->elementComparisonType = 0;
+ 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_->elementComparisonType = 0;
+ 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_->elementComparisonType = 0;
+ 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_->elementComparisonType = 0;
+ 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_->elementComparisonType = that.m_search_->elementComparisonType;
+ 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-4.8.1/i18n/selfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/selfmt.cpp
new file mode 100644
index 00000000000..0945f036c77
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/selfmt.cpp
@@ -0,0 +1,195 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Copyright (C) 2010 , Yahoo! Inc.
+ ********************************************************************
+ *
+ * File SELFMT.CPP
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 11/11/09 kirtig Finished first cut of implementation.
+ * 11/16/09 kirtig Improved version
+ ********************************************************************/
+
+#include <typeinfo> // for 'typeid' to work
+
+#include "unicode/messagepattern.h"
+#include "unicode/rbnf.h"
+#include "unicode/selfmt.h"
+#include "unicode/uchar.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/umsg.h"
+#include "unicode/ustring.h"
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "messageimpl.h"
+#include "patternprops.h"
+#include "selfmtimpl.h"
+#include "uassert.h"
+#include "ustrfmt.h"
+#include "util.h"
+#include "uvector.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat)
+
+static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0};
+
+SelectFormat::SelectFormat(const UnicodeString& pat,
+ UErrorCode& status) : msgPattern(status) {
+ applyPattern(pat, status);
+}
+
+SelectFormat::SelectFormat(const SelectFormat& other) : Format(other),
+ msgPattern(other.msgPattern) {
+}
+
+SelectFormat::~SelectFormat() {
+}
+
+void
+SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ msgPattern.parseSelectStyle(newPattern, NULL, status);
+ if (U_FAILURE(status)) {
+ msgPattern.clear();
+ }
+}
+
+UnicodeString&
+SelectFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ if (obj.getType() == Formattable::kString) {
+ return format(obj.getString(status), appendTo, pos, status);
+ } else {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+}
+
+UnicodeString&
+SelectFormat::format(const UnicodeString& keyword,
+ UnicodeString& appendTo,
+ FieldPosition& /*pos */,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ // Check for the validity of the keyword
+ if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) {
+ status = U_ILLEGAL_ARGUMENT_ERROR; // Invalid formatting argument.
+ }
+ if (msgPattern.countParts() == 0) {
+ status = U_INVALID_STATE_ERROR;
+ return appendTo;
+ }
+ int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status);
+ if (!MessageImpl::jdkAposMode(msgPattern)) {
+ int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
+ int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
+ appendTo.append(msgPattern.getPatternString(),
+ patternStart,
+ msgPattern.getPatternIndex(msgLimit) - patternStart);
+ return appendTo;
+ }
+ // JDK compatibility mode: Remove SKIP_SYNTAX.
+ return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
+}
+
+UnicodeString&
+SelectFormat::toPattern(UnicodeString& appendTo) {
+ if (0 == msgPattern.countParts()) {
+ appendTo.setToBogus();
+ } else {
+ appendTo.append(msgPattern.getPatternString());
+ }
+ return appendTo;
+}
+
+
+int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex,
+ const UnicodeString& keyword, UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return 0;
+ }
+ UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5);
+ int32_t count = pattern.countParts();
+ int32_t msgStart=0;
+ // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern.
+ do {
+ const MessagePattern::Part& part=pattern.getPart(partIndex++);
+ const UMessagePatternPartType type=part.getType();
+ if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
+ break;
+ }
+ // part is an ARG_SELECTOR followed by a message
+ if(pattern.partSubstringMatches(part, keyword)) {
+ // keyword matches
+ return partIndex;
+ } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) {
+ msgStart=partIndex;
+ }
+ partIndex=pattern.getLimitPartIndex(partIndex);
+ } while(++partIndex<count);
+ return msgStart;
+}
+
+Format* SelectFormat::clone() const
+{
+ return new SelectFormat(*this);
+}
+
+SelectFormat&
+SelectFormat::operator=(const SelectFormat& other) {
+ if (this != &other) {
+ msgPattern = other.msgPattern;
+ }
+ return *this;
+}
+
+UBool
+SelectFormat::operator==(const Format& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (!Format::operator==(other)) {
+ return FALSE;
+ }
+ const SelectFormat& o = (const SelectFormat&)other;
+ return msgPattern == o.msgPattern;
+}
+
+UBool
+SelectFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+void
+SelectFormat::parseObject(const UnicodeString& /*source*/,
+ Formattable& /*result*/,
+ ParsePosition& pos) const
+{
+ // Parsing not supported.
+ pos.setErrorIndex(pos.getIndex());
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/selfmtimpl.h b/Build/source/libs/icu/icu-4.8.1/i18n/selfmtimpl.h
new file mode 100644
index 00000000000..dea814a8795
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/selfmtimpl.h
@@ -0,0 +1,92 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Copyright (C) 2010 , Yahoo! Inc.
+ ********************************************************************
+ * File selectfmtimpl.h
+ *
+ * Date Name Description
+ * 11/11/09 kirtig Finished first cut of implementation.
+ *********************************************************************/
+
+
+#ifndef SELFMTIMPL
+#define SELFMTIMPL
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/locid.h"
+#include "unicode/parseerr.h"
+#include "unicode/utypes.h"
+#include "uvector.h"
+#include "hash.h"
+
+U_NAMESPACE_BEGIN
+
+#define DOT ((UChar)0x002E)
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define SLASH ((UChar)0x002F)
+#define BACKSLASH ((UChar)0x005C)
+#define SPACE ((UChar)0x0020)
+#define TAB ((UChar)0x0009)
+#define QUOTATION_MARK ((UChar)0x0022)
+#define ASTERISK ((UChar)0x002A)
+#define COMMA ((UChar)0x002C)
+#define HYPHEN ((UChar)0x002D)
+#define U_ZERO ((UChar)0x0030)
+#define U_ONE ((UChar)0x0031)
+#define U_TWO ((UChar)0x0032)
+#define U_THREE ((UChar)0x0033)
+#define U_FOUR ((UChar)0x0034)
+#define U_FIVE ((UChar)0x0035)
+#define U_SIX ((UChar)0x0036)
+#define U_SEVEN ((UChar)0x0037)
+#define U_EIGHT ((UChar)0x0038)
+#define U_NINE ((UChar)0x0039)
+#define COLON ((UChar)0x003A)
+#define SEMI_COLON ((UChar)0x003B)
+#define CAP_A ((UChar)0x0041)
+#define CAP_B ((UChar)0x0042)
+#define CAP_R ((UChar)0x0052)
+#define CAP_Z ((UChar)0x005A)
+#define LOWLINE ((UChar)0x005F)
+#define LEFTBRACE ((UChar)0x007B)
+#define RIGHTBRACE ((UChar)0x007D)
+
+#define LOW_A ((UChar)0x0061)
+#define LOW_B ((UChar)0x0062)
+#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_J ((UChar)0x006a)
+#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_X ((UChar)0x0078)
+#define LOW_Y ((UChar)0x0079)
+#define LOW_Z ((UChar)0x007A)
+
+class UnicodeSet;
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // SELFMTIMPL
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/simpletz.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/simpletz.cpp
new file mode 100644
index 00000000000..fb960bbf01a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/simpletz.cpp
@@ -0,0 +1,1221 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2010, 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 <typeinfo> // for 'typeid' to work
+
+#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) ||
+ (typeid(*this) == typeid(that) &&
+ 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 (typeid(*this) != typeid(other)) 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 (!useDaylight) {
+ 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 (!useDaylight) {
+ 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 (useDaylight) {
+ 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;
+ }
+ // Check for Null pointer
+ if (dtRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ // For now, use ID + "(DST)" as the name
+ dstRule = new AnnualTimeZoneRule(tzid+DST_STR, getRawOffset(), getDSTSavings(),
+ dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
+
+ // Check for Null pointer
+ if (dstRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+
+ // 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;
+ }
+
+ // Check for Null pointer
+ if (dtRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ // For now, use ID + "(STD)" as the name
+ stdRule = new AnnualTimeZoneRule(tzid+STD_STR, getRawOffset(), 0,
+ dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
+
+ //Check for Null pointer
+ if (stdRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+
+ // 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);
+ }
+ // Check for null pointers.
+ if (initialRule == NULL || firstTransition == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+
+ } else {
+ // Create a TimeZoneRule for initial time
+ initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
+ // Check for null pointer.
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ }
+
+ transitionRulesInitialized = true;
+}
+
+int32_t
+SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
+ return (useDaylight) ? 2 : 0;
+}
+
+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-4.8.1/i18n/smpdtfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfmt.cpp
new file mode 100644
index 00000000000..d1df7eda8ba
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfmt.cpp
@@ -0,0 +1,3556 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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/uniset.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 "patternprops.h"
+#include "fphdlimp.h"
+#include "gregoimp.h"
+#include "hebrwcal.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "umutex.h"
+#include "tzfmt.h"
+#include <float.h>
+#include "smpdtfst.h"
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+#include <stdio.h>
+#endif
+
+// *****************************************************************************
+// class SimpleDateFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+static const UChar PATTERN_CHAR_BASE = 0x40;
+
+/**
+ * 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 */
+static const UChar gUt[] = {0x0055, 0x0054, 0x0000}; // "UT"
+static const UChar gUtc[] = {0x0055, 0x0054, 0x0043, 0x0000}; // "UT"
+
+typedef enum GmtPatSize {
+ kGmtLen = 3,
+ kGmtPatLen = 6,
+ kNegHmsLen = 9,
+ kNegHmLen = 6,
+ kPosHmsLen = 9,
+ kPosHmLen = 6,
+ kUtLen = 2,
+ kUtcLen = 3
+} GmtPatSize;
+
+// Stuff needed for numbering system overrides
+
+typedef enum OvrStrType {
+ kOvrStrDate = 0,
+ kOvrStrTime = 1,
+ kOvrStrBoth = 2
+} OvrStrType;
+
+static const UDateFormatField kDateFields[] = {
+ UDAT_YEAR_FIELD,
+ UDAT_MONTH_FIELD,
+ UDAT_DATE_FIELD,
+ UDAT_DAY_OF_YEAR_FIELD,
+ UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
+ UDAT_WEEK_OF_YEAR_FIELD,
+ UDAT_WEEK_OF_MONTH_FIELD,
+ UDAT_YEAR_WOY_FIELD,
+ UDAT_EXTENDED_YEAR_FIELD,
+ UDAT_JULIAN_DAY_FIELD,
+ UDAT_STANDALONE_DAY_FIELD,
+ UDAT_STANDALONE_MONTH_FIELD,
+ UDAT_QUARTER_FIELD,
+ UDAT_STANDALONE_QUARTER_FIELD };
+static const int8_t kDateFieldsCount = 13;
+
+static const UDateFormatField kTimeFields[] = {
+ UDAT_HOUR_OF_DAY1_FIELD,
+ UDAT_HOUR_OF_DAY0_FIELD,
+ UDAT_MINUTE_FIELD,
+ UDAT_SECOND_FIELD,
+ UDAT_FRACTIONAL_SECOND_FIELD,
+ UDAT_HOUR1_FIELD,
+ UDAT_HOUR0_FIELD,
+ UDAT_MILLISECONDS_IN_DAY_FIELD,
+ UDAT_TIMEZONE_RFC_FIELD };
+static const int8_t kTimeFieldsCount = 9;
+
+
+// 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
+
+/*
+ * The field range check bias for each UDateFormatField.
+ * The bias is added to the minimum and maximum values
+ * before they are compared to the parsed number.
+ * For example, the calendar stores zero-based month numbers
+ * but the parsed month numbers start at 1, so the bias is 1.
+ *
+ * A value of -1 means that the value is not checked.
+ */
+static const int32_t gFieldRangeBias[] = {
+ -1, // 'G' - UDAT_ERA_FIELD
+ -1, // 'y' - UDAT_YEAR_FIELD
+ 1, // 'M' - UDAT_MONTH_FIELD
+ 0, // 'd' - UDAT_DATE_FIELD
+ -1, // 'k' - UDAT_HOUR_OF_DAY1_FIELD
+ -1, // 'H' - UDAT_HOUR_OF_DAY0_FIELD
+ 0, // 'm' - UDAT_MINUTE_FIELD
+ 0, // 's' - UDAT_SEOND_FIELD
+ -1, // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
+ -1, // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
+ -1, // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
+ -1, // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?)
+ -1, // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?)
+ -1, // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?)
+ -1, // 'a' - UDAT_AM_PM_FIELD
+ -1, // 'h' - UDAT_HOUR1_FIELD
+ -1, // 'K' - UDAT_HOUR0_FIELD
+ -1, // 'z' - UDAT_TIMEZONE_FIELD
+ -1, // 'Y' - UDAT_YEAR_WOY_FIELD
+ -1, // 'e' - UDAT_DOW_LOCAL_FIELD
+ -1, // 'u' - UDAT_EXTENDED_YEAR_FIELD
+ -1, // 'g' - UDAT_JULIAN_DAY_FIELD
+ -1, // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD
+ -1, // 'Z' - UDAT_TIMEZONE_RFC_FIELD
+ -1, // 'v' - UDAT_TIMEZONE_GENERIC_FIELD
+ 0, // 'c' - UDAT_STANDALONE_DAY_FIELD
+ 1, // 'L' - UDAT_STANDALONE_MONTH_FIELD
+ -1, // 'Q' - UDAT_QUARTER_FIELD (1-4?)
+ -1, // 'q' - UDAT_STANDALONE_QUARTER_FIELD
+ -1 // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
+};
+
+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);
+
+ }
+ if (fNumberFormatters) {
+ uprv_free(fNumberFormatters);
+ }
+ if (fTimeZoneFormat) {
+ delete fTimeZoneFormat;
+ }
+
+ while (fOverrideList) {
+ NSOverride *cur = fOverrideList;
+ fOverrideList = cur->next;
+ delete cur->nf;
+ uprv_free(cur);
+ }
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
+ : fLocale(Locale::getDefault()),
+ fSymbols(NULL),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+ construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ UErrorCode &status)
+: fPattern(pattern),
+ fLocale(Locale::getDefault()),
+ fSymbols(NULL),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+ fDateOverride.setToBogus();
+ fTimeOverride.setToBogus();
+ initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+
+}
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ const UnicodeString& override,
+ UErrorCode &status)
+: fPattern(pattern),
+ fLocale(Locale::getDefault()),
+ fSymbols(NULL),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+ fDateOverride.setTo(override);
+ fTimeOverride.setToBogus();
+ initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+
+ processOverrideString(fLocale,override,kOvrStrBoth,status);
+
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ const Locale& locale,
+ UErrorCode& status)
+: fPattern(pattern),
+ fLocale(locale),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+
+ fDateOverride.setToBogus();
+ fTimeOverride.setToBogus();
+
+ initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ const UnicodeString& override,
+ const Locale& locale,
+ UErrorCode& status)
+: fPattern(pattern),
+ fLocale(locale),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+
+ fDateOverride.setTo(override);
+ fTimeOverride.setToBogus();
+
+ initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+
+ processOverrideString(locale,override,kOvrStrBoth,status);
+
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ DateFormatSymbols* symbolsToAdopt,
+ UErrorCode& status)
+: fPattern(pattern),
+ fLocale(Locale::getDefault()),
+ fSymbols(symbolsToAdopt),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+
+ fDateOverride.setToBogus();
+ fTimeOverride.setToBogus();
+
+ 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)),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(NULL)
+{
+
+ fDateOverride.setToBogus();
+ fTimeOverride.setToBogus();
+
+ 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),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(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),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(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;
+ }
+ }
+
+ fDateOverride.setToBogus();
+ fTimeOverride.setToBogus();
+
+ initialize(fLocale, status);
+ if(U_SUCCESS(status)) {
+ initializeDefaultCentury();
+ }
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
+: DateFormat(other),
+ fSymbols(NULL),
+ fTimeZoneFormat(NULL),
+ fGMTFormatters(NULL),
+ fNumberFormatters(NULL),
+ fOverrideList(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;
+
+ // TimeZoneFormat in ICU4C only depends on a locale for now
+ if (fLocale != other.fLocale) {
+ delete fTimeZoneFormat;
+ }
+
+ 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);
+ UResourceBundle *currentBundle;
+
+ 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,*ovrStr;
+ int32_t resStrLen,ovrStrLen = 0;
+ fDateOverride.setToBogus();
+ fTimeOverride.setToBogus();
+
+ // 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
+
+ currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
+ if (U_FAILURE(status)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ switch (ures_getType(currentBundle)) {
+ case URES_STRING: {
+ resStr = ures_getString(currentBundle, &resStrLen, &status);
+ break;
+ }
+ case URES_ARRAY: {
+ resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+ ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+ fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);
+ break;
+ }
+ default: {
+ status = U_INVALID_FORMAT_ERROR;
+ ures_close(currentBundle);
+ return;
+ }
+ }
+ ures_close(currentBundle);
+
+ UnicodeString *tempus1 = new UnicodeString(TRUE, resStr, resStrLen);
+ // NULL pointer check
+ if (tempus1 == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ timeDateArray[0].adoptString(tempus1);
+
+ currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
+ if (U_FAILURE(status)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ switch (ures_getType(currentBundle)) {
+ case URES_STRING: {
+ resStr = ures_getString(currentBundle, &resStrLen, &status);
+ break;
+ }
+ case URES_ARRAY: {
+ resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+ ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+ fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
+ break;
+ }
+ default: {
+ status = U_INVALID_FORMAT_ERROR;
+ ures_close(currentBundle);
+ return;
+ }
+ }
+ ures_close(currentBundle);
+
+ UnicodeString *tempus2 = new UnicodeString(TRUE, resStr, resStrLen);
+ // Null pointer check
+ if (tempus2 == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ timeDateArray[1].adoptString(tempus2);
+
+ int32_t glueIndex = kDateTime;
+ int32_t patternsSize = ures_getSize(dateTimePatterns);
+ if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
+ // Get proper date time format
+ glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
+ }
+
+ resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &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) {
+ currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
+ if (U_FAILURE(status)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ switch (ures_getType(currentBundle)) {
+ case URES_STRING: {
+ resStr = ures_getString(currentBundle, &resStrLen, &status);
+ break;
+ }
+ case URES_ARRAY: {
+ resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+ ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+ fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
+ break;
+ }
+ default: {
+ status = U_INVALID_FORMAT_ERROR;
+ ures_close(currentBundle);
+ return;
+ }
+ }
+ fPattern.setTo(TRUE, resStr, resStrLen);
+ ures_close(currentBundle);
+ }
+ else if (dateStyle != kNone) {
+ currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
+ if (U_FAILURE(status)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ switch (ures_getType(currentBundle)) {
+ case URES_STRING: {
+ resStr = ures_getString(currentBundle, &resStrLen, &status);
+ break;
+ }
+ case URES_ARRAY: {
+ resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
+ ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
+ fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
+ break;
+ }
+ default: {
+ status = U_INVALID_FORMAT_ERROR;
+ ures_close(currentBundle);
+ return;
+ }
+ }
+ fPattern.setTo(TRUE, resStr, resStrLen);
+ ures_close(currentBundle);
+ }
+
+ // 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);
+ // Null pointer check
+ if (fSymbols == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+}
+
+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);
+ DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
+ if (decfmt != NULL) {
+ decfmt->setDecimalSeparatorAlwaysShown(FALSE);
+ }
+ fNumberFormat->setParseIntegerOnly(TRUE);
+ fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
+
+ //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
+
+ initNumberFormatters(locale,status);
+
+ }
+ 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;
+ FieldPositionOnlyHandler handler(pos);
+ return _format(cal, appendTo, handler, status);
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
+ FieldPositionIterator* posIter, UErrorCode& status) const
+{
+ FieldPositionIteratorHandler handler(posIter, status);
+ return _format(cal, appendTo, handler, status);
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionHandler& handler,
+ UErrorCode& status) const
+{
+ Calendar *workCal = &cal;
+ TimeZone *backupTZ = NULL;
+ if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
+ // Different calendar type
+ // We use the time and time zone from the input calendar, but
+ // do not use the input calendar for field calculation.
+ UDate t = cal.getTime(status);
+ fCalendar->setTime(t, status);
+ backupTZ = fCalendar->getTimeZone().clone();
+ fCalendar->setTimeZone(cal.getTimeZone());
+ workCal = fCalendar;
+ }
+
+ 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, handler, *workCal, 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, handler, *workCal, status);
+ }
+
+ if (backupTZ != NULL) {
+ // Restore the original time zone
+ fCalendar->adoptTimeZone(backupTZ);
+ }
+
+ return appendTo;
+}
+
+//----------------------------------------------------------------------
+
+/* Map calendar field into calendar field level.
+ * the larger the level, the smaller the field unit.
+ * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10,
+ * UCAL_MONTH level is 20.
+ * NOTE: if new fields adds in, the table needs to update.
+ */
+const int32_t
+SimpleDateFormat::fgCalendarFieldToLevel[] =
+{
+ /*GyM*/ 0, 10, 20,
+ /*wW*/ 20, 30,
+ /*dDEF*/ 30, 20, 30, 30,
+ /*ahHm*/ 40, 50, 50, 60,
+ /*sS..*/ 70, 80,
+ /*z?Y*/ 0, 0, 10,
+ /*eug*/ 30, 10, 0,
+ /*A*/ 40
+};
+
+
+/* Map calendar field LETTER into calendar field level.
+ * the larger the level, the smaller the field unit.
+ * NOTE: if new fields adds in, the table needs to update.
+ */
+const int32_t
+SimpleDateFormat::fgPatternCharToLevel[] = {
+ // A B C D E F G H I J K L M N O
+ -1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, -1,
+ // P Q R S T U V W X Y Z
+ -1, 20, -1, 80, -1, -1, 0, 30, -1, 10, 0, -1, -1, -1, -1, -1,
+ // a b c d e f g h i j k l m n o
+ -1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, -1, 60, -1, -1,
+ // p q r s t u v w x y z
+ -1, 20, -1, 70, -1, 10, 0, 20, -1, 10, 0, -1, -1, -1, -1, -1
+};
+
+
+// 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_DOW_LOCAL,
+ /*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(NumberFormat *currentNumberFormat,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 (offset == 0) {
+ // use GMT zero format
+ appendTo += fSymbols->fGmtZero;
+ } else {
+ if (isDefaultGMTFormat()) {
+ formatGMTDefault(currentNumberFormat,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) >= fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx]) {
+ parsed.getArray(parsedCount);
+ if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
+ return (int32_t)(-1 * (int64_t)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) >= fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx]) {
+ parsed.getArray(parsedCount);
+ if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
+ return (int32_t)((int64_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 * (int64_t)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)((int64_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(NumberFormat *currentNumberFormat,UnicodeString &appendTo, int32_t offset) const {
+ if (offset < 0) {
+ appendTo.append(gGmtMinus, 4);
+ offset = -offset; // suppress the '-' sign for text display.
+ }else{
+ appendTo.append(gGmtPlus, 4);
+ }
+
+ 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(currentNumberFormat,appendTo, hour, 2, 2);
+ appendTo += (UChar)0x003A /*':'*/;
+ zeroPaddingNumber(currentNumberFormat,appendTo, min, 2, 2);
+ if (sec != 0) {
+ appendTo += (UChar)0x003A /*':'*/;
+ zeroPaddingNumber(currentNumberFormat,appendTo, sec, 2, 2);
+ }
+}
+
+int32_t
+SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const {
+ int32_t start = pos.getIndex();
+ NumberFormat *currentNumberFormat = getNumberFormatByIndex(UDAT_TIMEZONE_RFC_FIELD);
+
+ if (start + kUtLen + 1 >= text.length()) {
+ pos.setErrorIndex(start);
+ return 0;
+ }
+
+ int32_t cur = start;
+ // "GMT"
+ if (text.compare(start, kGmtLen, gGmt) == 0) {
+ cur += kGmtLen;
+ } else if (text.compare(start, kUtLen, gUt) == 0) {
+ cur += kUtLen;
+ } else {
+ pos.setErrorIndex(start);
+ return 0;
+ }
+ // 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,currentNumberFormat);
+ 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,currentNumberFormat);
+ 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,currentNumberFormat);
+ 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 = NULL; //initialized it to avoid warning
+ 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);
+ GregorianCalendar *gcal = new GregorianCalendar(TimeZone::createTimeZone(UnicodeString(gEtcUTC)), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ SimpleDateFormat *sdf = (SimpleDateFormat*)this->clone();
+ sdf->adoptCalendar(gcal);
+ sdf->applyPattern(*hourPattern);
+
+ // This prevents an hours format pattern like "-HH:mm:ss" from matching
+ // in a string like "GMT-07:00 10:08:11 PM"
+ sdf->setLenient(FALSE);
+
+ fGMTFormatters[i]->adoptFormat(0, sdf);
+
+ // For parsing, we only allow Hms patterns to be equal or longer
+ // than its length with fixed minutes/seconds digits.
+ // See #6880
+ if (i == kGMTNegativeHMS || i == kGMTPositiveHMS) {
+ UnicodeString tmp;
+ Formattable tmpParam(60*60*1000, Formattable::kIsDate);
+ FieldPosition fpos(0);
+ fGMTFormatters[i]->format(&tmpParam, 1, tmp, fpos, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ if (i == kGMTNegativeHMS) {
+ fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx] = tmp.length();
+ } else {
+ fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx] = tmp.length();
+ }
+ }
+ }
+ } else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ umtx_unlock(&LOCK);
+}
+
+void
+SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
+ return;
+ }
+ umtx_lock(&LOCK);
+ if (fNumberFormatters == NULL) {
+ fNumberFormatters = (NumberFormat**)uprv_malloc(UDAT_FIELD_COUNT * sizeof(NumberFormat*));
+ if (fNumberFormatters) {
+ for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) {
+ fNumberFormatters[i] = fNumberFormat;
+ }
+ } else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ umtx_unlock(&LOCK);
+
+ processOverrideString(locale,fDateOverride,kOvrStrDate,status);
+ processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
+
+}
+
+void
+SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
+ if (str.isBogus()) {
+ return;
+ }
+ int32_t start = 0;
+ int32_t len;
+ UnicodeString nsName;
+ UnicodeString ovrField;
+ UBool moreToProcess = TRUE;
+
+ while (moreToProcess) {
+ int32_t delimiterPosition = str.indexOf(ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
+ if (delimiterPosition == -1) {
+ moreToProcess = FALSE;
+ len = str.length() - start;
+ } else {
+ len = delimiterPosition - start;
+ }
+ UnicodeString currentString(str,start,len);
+ int32_t equalSignPosition = currentString.indexOf(ULOC_KEYWORD_ASSIGN_UNICODE,0);
+ if (equalSignPosition == -1) { // Simple override string such as "hebrew"
+ nsName.setTo(currentString);
+ ovrField.setToBogus();
+ } else { // Field specific override string such as "y=hebrew"
+ nsName.setTo(currentString,equalSignPosition+1);
+ ovrField.setTo(currentString,0,1); // We just need the first character.
+ }
+
+ int32_t nsNameHash = nsName.hashCode();
+ // See if the numbering system is in the override list, if not, then add it.
+ NSOverride *cur = fOverrideList;
+ NumberFormat *nf = NULL;
+ UBool found = FALSE;
+ while ( cur && !found ) {
+ if ( cur->hash == nsNameHash ) {
+ nf = cur->nf;
+ found = TRUE;
+ }
+ cur = cur->next;
+ }
+
+ if (!found) {
+ cur = (NSOverride *)uprv_malloc(sizeof(NSOverride));
+ if (cur) {
+ char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
+ uprv_strcpy(kw,"numbers=");
+ nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
+
+ Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
+ nf = NumberFormat::createInstance(ovrLoc,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
+
+ if (U_SUCCESS(status)) {
+ nf->setGroupingUsed(FALSE);
+ DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(nf);
+ if (decfmt != NULL) {
+ decfmt->setDecimalSeparatorAlwaysShown(FALSE);
+ }
+ nf->setParseIntegerOnly(TRUE);
+ nf->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
+
+ cur->nf = nf;
+ cur->hash = nsNameHash;
+ cur->next = fOverrideList;
+ fOverrideList = cur;
+ }
+ else {
+ // clean up before returning
+ if (cur != NULL) {
+ uprv_free(cur);
+ }
+ return;
+ }
+
+ } else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ // Now that we have an appropriate number formatter, fill in the appropriate spaces in the
+ // number formatters table.
+
+ if (ovrField.isBogus()) {
+ switch (type) {
+ case kOvrStrDate:
+ case kOvrStrBoth: {
+ for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
+ fNumberFormatters[kDateFields[i]] = nf;
+ }
+ if (type==kOvrStrDate) {
+ break;
+ }
+ }
+ case kOvrStrTime : {
+ for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
+ fNumberFormatters[kTimeFields[i]] = nf;
+ }
+ break;
+ }
+ }
+ } else {
+ UChar ch = ovrField.charAt(0);
+ UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
+ UDateFormatField patternCharIndex;
+
+ // if the pattern character is unrecognized, signal an error and bail out
+ if (patternCharPtr == NULL) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
+
+ // Set the number formatter in the table
+ fNumberFormatters[patternCharIndex] = nf;
+ }
+
+ start = delimiterPosition + 1;
+ }
+}
+//---------------------------------------------------------------------
+void
+SimpleDateFormat::subFormat(UnicodeString &appendTo,
+ UChar ch,
+ int32_t count,
+ FieldPositionHandler& handler,
+ 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();
+ NumberFormat *currentNumberFormat;
+
+ UBool isHebrewCalendar = !strcmp(cal.getType(),"hebrew");
+
+ // 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;
+ }
+
+ currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
+ switch (patternCharIndex) {
+
+ // for any "G" symbol, write out the appropriate era string
+ // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name
+ case UDAT_ERA_FIELD:
+ if (count == 5)
+ _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
+ else if (count == 4)
+ _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
+ else
+ _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
+ break;
+
+ // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
+ // NEW: UTS#35:
+//Year y yy yyy yyyy yyyyy
+//AD 1 1 01 001 0001 00001
+//AD 12 12 12 012 0012 00012
+//AD 123 123 23 123 0123 00123
+//AD 1234 1234 34 1234 1234 01234
+//AD 12345 12345 45 12345 12345 12345
+ case UDAT_YEAR_FIELD:
+ case UDAT_YEAR_WOY_FIELD:
+ if(count == 2)
+ zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
+ else
+ zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
+ break;
+
+ // 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 ( isHebrewCalendar ) {
+ HebrewCalendar *hc = (HebrewCalendar*)&cal;
+ if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
+ value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
+ if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
+ value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
+ }
+ 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(currentNumberFormat,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(currentNumberFormat,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(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
+ else
+ zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
+ break;
+
+ case UDAT_FRACTIONAL_SECOND_FIELD:
+ // Fractional seconds left-justify
+ {
+ currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
+ currentNumberFormat->setMaximumIntegerDigits(maxIntCount);
+ if (count == 1) {
+ value /= 100;
+ } else if (count == 2) {
+ value /= 10;
+ }
+ FieldPosition p(0);
+ currentNumberFormat->format(value, appendTo, p);
+ if (count > 3) {
+ currentNumberFormat->setMinimumIntegerDigits(count - 3);
+ currentNumberFormat->format((int32_t)0, appendTo, p);
+ }
+ }
+ break;
+
+ // for "ee" or "e", use local numeric day-of-the-week
+ // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name
+ // for "EEEE" or "eeee", write out the wide day-of-the-week name
+ // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name
+ case UDAT_DOW_LOCAL_FIELD:
+ if ( count < 3 ) {
+ zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
+ break;
+ }
+ // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week,
+ // we want standard day-of-week, so first fix value to work for EEEEE-EEE.
+ value = cal.get(UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // fall through, do not break here
+ 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 < 3 ) {
+ zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
+ break;
+ }
+ // fall through to alpha DOW handling, but for that we don't want local day-of-week,
+ // we want standard day-of-week, so first fix value.
+ value = cal.get(UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (count == 5)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
+ fSymbols->fStandaloneNarrowWeekdaysCount);
+ else if (count == 4)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
+ fSymbols->fStandaloneWeekdaysCount);
+ else // count == 3
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
+ fSymbols->fStandaloneShortWeekdaysCount);
+ 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(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
+ else
+ zeroPaddingNumber(currentNumberFormat,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 TimeZone& tz = cal.getTimeZone();
+ UDate date = cal.getTime(status);
+ if (U_SUCCESS(status)) {
+ if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
+ if (count < 4) {
+ // "z", "zz", "zzz"
+ tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED, tz, date, zoneString);
+ } else {
+ // "zzzz"
+ tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
+ }
+ } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
+ if (count == 1) {
+ // "v"
+ tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
+ } else if (count == 4) {
+ // "vvvv"
+ tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
+ }
+ } else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
+ if (count == 1) {
+ // "V"
+ tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
+ } else if (count == 4) {
+ // "VVVV"
+ tzFormat()->format(UTZFMT_STYLE_LOCATION, tz, date, zoneString);
+ }
+ }
+ }
+ if (zoneString.isEmpty()) {
+ appendGMT(currentNumberFormat,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(currentNumberFormat,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(currentNumberFormat,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(currentNumberFormat,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(currentNumberFormat,appendTo, value, count, maxIntCount);
+ break;
+ }
+
+ handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
+}
+
+//----------------------------------------------------------------------
+
+NumberFormat *
+SimpleDateFormat::getNumberFormatByIndex(UDateFormatField index) const {
+ if (fNumberFormatters != NULL) {
+ return fNumberFormatters[index];
+ } else {
+ return fNumberFormat;
+ }
+}
+
+//----------------------------------------------------------------------
+void
+SimpleDateFormat::zeroPaddingNumber(NumberFormat *currentNumberFormat,UnicodeString &appendTo,
+ int32_t value, int32_t minDigits, int32_t maxDigits) const
+{
+ if (currentNumberFormat!=NULL) {
+ FieldPosition pos(0);
+
+ currentNumberFormat->setMinimumIntegerDigits(minDigits);
+ currentNumberFormat->setMaximumIntegerDigits(maxDigits);
+ currentNumberFormat->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, 0x59, 0x79, 0x75, 0x64, 0x65, 0x68, 0x48, 0x6D, 0x73, 0x53, 0x44, 0x46, 0x77, 0x57, 0x6B, 0x4B, 0x00}; /* "MYyudehHmsSDFwWkK" */
+
+/**
+ * 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
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t pos = parsePos.getIndex();
+ int32_t start = pos;
+
+ UBool ambiguousYear[] = { FALSE };
+ int32_t saveHebrewMonth = -1;
+ int32_t count = 0;
+
+ UBool lenient = isLenient();
+
+ // 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);
+
+ TimeZone *backupTZ = NULL;
+ Calendar *workCal = &cal;
+ if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
+ // Different calendar type
+ // We use the time/zone from the input calendar, but
+ // do not use the input calendar for field calculation.
+ fCalendar->setTime(cal.getTime(status),status);
+ if (U_FAILURE(status)) {
+ goto ExitParse;
+ }
+ backupTZ = fCalendar->getTimeZone().clone();
+ fCalendar->setTimeZone(cal.getTimeZone());
+ workCal = fCalendar;
+ }
+
+ 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) {
+ status = U_PARSE_ERROR;
+ goto ExitParse;
+ }
+ }
+
+ pos = subParse(text, pos, ch, count,
+ TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i);
+
+ // 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 = subParse(text, pos, ch, count,
+ FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i);
+
+ if (s == -pos-1) {
+ // era not present, in special cases allow this to continue
+ s++;
+
+ if (i+1 < fPattern.length()) {
+ // move to next pattern character
+ UChar ch = fPattern.charAt(i+1);
+
+ // check for whitespace
+ if (PatternProps::isWhiteSpace(ch)) {
+ i++;
+ // Advance over run in pattern
+ while ((i+1)<fPattern.length() &&
+ PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
+ ++i;
+ }
+ }
+ }
+ }
+ else if (s <= 0) {
+ status = U_PARSE_ERROR;
+ goto ExitParse;
+ }
+ pos = s;
+ }
+ }
+
+ // Handle literal pattern characters. These are any
+ // quoted characters and non-alphabetic unquoted
+ // characters.
+ else {
+
+ abutPat = -1; // End of any abutting fields
+
+ if (! matchLiterals(fPattern, i, text, pos, lenient)) {
+ status = U_PARSE_ERROR;
+ goto ExitParse;
+ }
+ }
+ }
+
+ // 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().
+ 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();
+ // Check for failed cloning.
+ if (copy == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto ExitParse;
+ }
+ 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();
+ // Check for failed cloning.
+ if (copy == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto ExitParse;
+ }
+ const TimeZone & tz = cal.getTimeZone();
+ BasicTimeZone *btz = NULL;
+
+ if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
+ || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
+ || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
+ || dynamic_cast<const VTimeZone *>(&tz) != NULL) {
+ 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;
+ }
+ }
+ExitParse:
+ // Set the parsed result if local calendar is used
+ // instead of the input calendar
+ if (U_SUCCESS(status) && workCal != &cal) {
+ cal.setTimeZone(workCal->getTimeZone());
+ cal.setTime(workCal->getTime(status), status);
+ }
+
+ // Restore the original time zone if required
+ if (backupTZ != NULL) {
+ fCalendar->adoptTimeZone(backupTZ);
+ }
+
+ // 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;
+}
+
+//----------------------------------------------------------------------
+UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
+ int32_t &patternOffset,
+ const UnicodeString &text,
+ int32_t &textOffset,
+ UBool lenient)
+{
+ UBool inQuote = FALSE;
+ UnicodeString literal;
+ int32_t i = patternOffset;
+
+ // scan pattern looking for contiguous literal characters
+ for ( ; i < pattern.length(); i += 1) {
+ UChar ch = pattern.charAt(i);
+
+ if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // unquoted [A-Za-z]
+ break;
+ }
+
+ if (ch == QUOTE) {
+ // Match a quote literal ('') inside OR outside of quotes
+ if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
+ i += 1;
+ } else {
+ inQuote = !inQuote;
+ continue;
+ }
+ }
+
+ literal += ch;
+ }
+
+ // at this point, literal contains the literal text
+ // and i is the index of the next non-literal pattern character.
+ int32_t p;
+ int32_t t = textOffset;
+
+ if (lenient) {
+ // trim leading, trailing whitespace from
+ // the literal text
+ literal.trim();
+
+ // ignore any leading whitespace in the text
+ while (t < text.length() && u_isWhitespace(text.charAt(t))) {
+ t += 1;
+ }
+ }
+
+ for (p = 0; p < literal.length() && t < text.length(); p += 1, t += 1) {
+ UBool needWhitespace = FALSE;
+
+ while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
+ needWhitespace = TRUE;
+ p += 1;
+ }
+
+ if (needWhitespace) {
+ int32_t tStart = t;
+
+ while (t < text.length()) {
+ UChar tch = text.charAt(t);
+
+ if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
+ break;
+ }
+
+ t += 1;
+ }
+
+ // TODO: should we require internal spaces
+ // in lenient mode? (There won't be any
+ // leading or trailing spaces)
+ if (!lenient && t == tStart) {
+ // didn't find matching whitespace:
+ // an error in strict mode
+ return FALSE;
+ }
+
+ // In strict mode, this run of whitespace
+ // may have been at the end.
+ if (p >= literal.length()) {
+ break;
+ }
+ }
+
+ if (t >= text.length() || literal.charAt(p) != text.charAt(t)) {
+ // Ran out of text, or found a non-matching character:
+ // OK in lenient mode, an error in strict mode.
+ if (lenient) {
+ break;
+ }
+
+ return FALSE;
+ }
+ }
+
+ // At this point if we're in strict mode we have a complete match.
+ // If we're in lenient mode we may have a partial match, or no
+ // match at all.
+ if (p <= 0) {
+ // no match. Pretend it matched a run of whitespace
+ // and ignorables in the text.
+ const UnicodeSet *ignorables = NULL;
+ UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), pattern.charAt(i));
+
+ if (patternCharPtr != NULL) {
+ UDateFormatField patternCharIndex = (UDateFormatField) (patternCharPtr - DateFormatSymbols::getPatternUChars());
+
+ ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
+ }
+
+ for (t = textOffset; t < text.length(); t += 1) {
+ UChar ch = text.charAt(t);
+
+ if (ignorables == NULL || !ignorables->contains(ch)) {
+ break;
+ }
+ }
+ }
+
+ // if we get here, we've got a complete match.
+ patternOffset = i - 1;
+ textOffset = t;
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------
+
+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)
+ {
+ // Adjustment for Hebrew Calendar month Adar II
+ if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
+ cal.set(field,6);
+ }
+ else {
+ 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[], int32_t& saveHebrewMonth, Calendar& cal,
+ int32_t patLoc) const
+{
+ Formattable number;
+ int32_t value = 0;
+ int32_t i;
+ int32_t ps = 0;
+ ParsePosition pos(0);
+ UDateFormatField patternCharIndex;
+ NumberFormat *currentNumberFormat;
+ UnicodeString temp;
+ UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
+ UBool lenient = isLenient();
+ UBool gotNumber = FALSE;
+
+#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());
+ currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
+ 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) /*||*/ && !PatternProps::isWhiteSpace(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_HOUR_OF_DAY0_FIELD ||
+ patternCharIndex == UDAT_HOUR1_FIELD ||
+ patternCharIndex == UDAT_HOUR0_FIELD ||
+ patternCharIndex == UDAT_DOW_LOCAL_FIELD ||
+ patternCharIndex == UDAT_STANDALONE_DAY_FIELD ||
+ patternCharIndex == UDAT_MONTH_FIELD ||
+ patternCharIndex == UDAT_STANDALONE_MONTH_FIELD ||
+ patternCharIndex == UDAT_QUARTER_FIELD ||
+ patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD ||
+ 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,currentNumberFormat);
+
+ int32_t txtLoc = pos.getIndex();
+
+ if (txtLoc > parseStart) {
+ value = number.getLong();
+ gotNumber = TRUE;
+
+ // suffix processing
+ if (value < 0 ) {
+ txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
+ if (txtLoc != pos.getIndex()) {
+ value *= -1;
+ }
+ }
+ else {
+ txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
+ }
+
+ // Check the range of the value
+ int32_t bias = gFieldRangeBias[patternCharIndex];
+
+ if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
+ return -start;
+ }
+
+ pos.setIndex(txtLoc);
+ }
+ }
+
+ // Make sure that we got a number if
+ // we want one, and didn't get one
+ // if we don't want one.
+ switch (patternCharIndex) {
+ case UDAT_HOUR_OF_DAY1_FIELD:
+ case UDAT_HOUR_OF_DAY0_FIELD:
+ case UDAT_HOUR1_FIELD:
+ case UDAT_HOUR0_FIELD:
+ // special range check for hours:
+ if (value < 0 || value > 24) {
+ return -start;
+ }
+
+ // fall through to gotNumber check
+
+ case UDAT_YEAR_FIELD:
+ case UDAT_YEAR_WOY_FIELD:
+ case UDAT_FRACTIONAL_SECOND_FIELD:
+ // these must be a number
+ if (! gotNumber) {
+ return -start;
+ }
+
+ break;
+
+ case UDAT_DOW_LOCAL_FIELD:
+ case UDAT_STANDALONE_DAY_FIELD:
+ case UDAT_MONTH_FIELD:
+ case UDAT_STANDALONE_MONTH_FIELD:
+ case UDAT_QUARTER_FIELD:
+ case UDAT_STANDALONE_QUARTER_FIELD:
+ // in strict mode, these can only
+ // be a number if count <= 2
+ if (!lenient && gotNumber && count > 2) {
+ // We have a string pattern in strict mode
+ // but the input parsed as a number. Ignore
+ // the fact that the input parsed as a number
+ // and try to match it as a string. (Some
+ // locales have numbers for the month names.)
+ gotNumber = FALSE;
+ pos.setIndex(start);
+ }
+
+ break;
+
+ default:
+ // we check the rest of the fields below.
+ break;
+ }
+
+ switch (patternCharIndex) {
+ case UDAT_ERA_FIELD:
+ if (count == 5) {
+ ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal);
+ } else if (count == 4) {
+ ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal);
+ } else {
+ ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
+ }
+
+ // check return position, if it equals -start, then matchString error
+ // special case the return code so we don't necessarily fail out until we
+ // verify no year information also
+ if (ps == -start)
+ ps--;
+
+ return ps;
+
+ 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 ((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);
+
+ // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
+ if (saveHebrewMonth >= 0) {
+ HebrewCalendar *hc = (HebrewCalendar*)&cal;
+ if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
+ cal.set(UCAL_MONTH,saveHebrewMonth);
+ } else {
+ cal.set(UCAL_MONTH,saveHebrewMonth-1);
+ }
+ saveHebrewMonth = -1;
+ }
+ return pos.getIndex();
+
+ case UDAT_YEAR_WOY_FIELD:
+ // Comment is the same as for UDAT_Year_FIELDs - look above
+ if ((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 (gotNumber) // i.e., M or MM.
+ {
+ // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether
+ // or not it was a leap year. We may or may not yet know what year it is, so might have to delay checking until
+ // the year is parsed.
+ if (!strcmp(cal.getType(),"hebrew")) {
+ HebrewCalendar *hc = (HebrewCalendar*)&cal;
+ if (cal.isSet(UCAL_YEAR)) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
+ cal.set(UCAL_MONTH, value);
+ } else {
+ cal.set(UCAL_MONTH, value - 1);
+ }
+ } else {
+ saveHebrewMonth = value;
+ }
+ } else {
+ // 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 (gotNumber) // 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;
+
+ // fall through to set field
+
+ case UDAT_HOUR_OF_DAY0_FIELD:
+ 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_DOW_LOCAL_FIELD:
+ if (gotNumber) // i.e., e or ee
+ {
+ // [We computed 'value' above.]
+ cal.set(UCAL_DOW_LOCAL, value);
+ return pos.getIndex();
+ }
+ // else for eee-eeeee fall through to handling of EEE-EEEEE
+ // fall through, do not break here
+ case UDAT_DAY_OF_WEEK_FIELD:
+ {
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 (EEEE) first:
+ int32_t newStart = 0;
+ if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fWeekdays, fSymbols->fWeekdaysCount, cal)) > 0)
+ return newStart;
+ // EEEE failed, now try EEE
+ else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, cal)) > 0)
+ return newStart;
+ // EEE failed, now try EEEEE
+ else
+ return matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, cal);
+ }
+
+ case UDAT_STANDALONE_DAY_FIELD:
+ {
+ if (gotNumber) // c or cc
+ {
+ // [We computed 'value' above.]
+ cal.set(UCAL_DOW_LOCAL, value);
+ return pos.getIndex();
+ }
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 (cccc) first:
+ int32_t newStart = 0;
+ if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, cal)) > 0)
+ return newStart;
+ else // cccc failed, now try ccc
+ 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;
+
+ // fall through to set field
+
+ case UDAT_HOUR0_FIELD:
+ cal.set(UCAL_HOUR, value);
+ return pos.getIndex();
+
+ case UDAT_QUARTER_FIELD:
+ if (gotNumber) // 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 (gotNumber) // 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,currentNumberFormat);
+ 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
+ // Is this standalone Localized GMT zero or GMT/UT/UTC?
+ int32_t gmtLen = 0;
+ if (text.compare(start, fSymbols->fGmtZero.length(), fSymbols->fGmtZero) == 0) {
+ gmtLen = fSymbols->fGmtZero.length();
+ } else if (text.compare(start, kGmtLen, gGmt) == 0) {
+ gmtLen = kGmtLen;
+ } else if (text.compare(start, kUtcLen, gUtc) == 0) {
+ gmtLen = kUtcLen;
+ } else if (text.compare(start, kUtLen, gUt) == 0) {
+ gmtLen = kUtLen;
+ }
+ // If we parse the string to the end, we can exit here.
+ // If any characters follow, we still need to proceed to the
+ // next step. Otherwise, all time zone names starting with GMT/UT/UTC
+ // (for example, "UTT") will fail.
+ if (gmtLen > 0 && ((text.length() - start) == gmtLen)) {
+ TimeZone *tz = TimeZone::createTimeZone(UNICODE_STRING("Etc/GMT", 7));
+ cal.adoptTimeZone(tz);
+ return start + gmtLen;
+ }
+
+ // Step 4
+ // At this point, check for named time zones by looking through
+ // the locale data.
+ if (patternCharIndex != UDAT_TIMEZONE_RFC_FIELD) {
+ UTimeZoneTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ ParsePosition tmpPos(start);
+ UnicodeString parsedID;
+
+ switch (patternCharIndex) {
+ case UDAT_TIMEZONE_FIELD:
+ if (count < 4) {
+ tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED, text, tmpPos, parsedID, &parsedTimeType);
+ } else {
+ tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_LONG, text, tmpPos, parsedID, &parsedTimeType);
+ }
+ break;
+ case UDAT_TIMEZONE_GENERIC_FIELD:
+ if (count < 4) {
+ tzFormat()->parse(UTZFMT_STYLE_GENERIC_SHORT, text, tmpPos, parsedID, &parsedTimeType);
+ } else {
+ tzFormat()->parse(UTZFMT_STYLE_GENERIC_LONG, text, tmpPos, parsedID, &parsedTimeType);
+ }
+ break;
+ case UDAT_TIMEZONE_SPECIAL_FIELD:
+ if (count < 4) {
+ tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_SHORT, text, tmpPos, parsedID, &parsedTimeType);
+ } else {
+ tzFormat()->parse(UTZFMT_STYLE_LOCATION, text, tmpPos, parsedID, &parsedTimeType);
+ }
+ break;
+ default:
+ break;
+ }
+ if (tmpPos.getErrorIndex() < 0) {
+ if (parsedTimeType == UTZFMT_TIME_TYPE_STANDARD) {
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
+ } else if (parsedTimeType == UTZFMT_TIME_TYPE_DAYLIGHT) {
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
+ }
+
+ UnicodeString current;
+ cal.getTimeZone().getID(current);
+ if (parsedID != current) {
+ TimeZone *tz = TimeZone::createTimeZone(parsedID);
+ cal.adoptTimeZone(tz);
+ }
+ return tmpPos.getIndex();
+ }
+ }
+ // Step 5
+ // If we saw standalone GMT zero pattern, then use GMT.
+ if (gmtLen > 0) {
+ TimeZone *tz = TimeZone::createTimeZone(UNICODE_STRING("Etc/GMT", 7));
+ cal.adoptTimeZone(tz);
+ return start + gmtLen;
+ }
+
+ // 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,currentNumberFormat);
+ if (pos.getIndex() != parseStart) {
+ int32_t value = number.getLong();
+
+ // Check the range of the value
+ int32_t bias = gFieldRangeBias[patternCharIndex];
+
+ if (bias < 0 || (value >= cal.getMinimum(field) + bias && value <= cal.getMaximum(field) + bias)) {
+ cal.set(field, value);
+ 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,
+ NumberFormat *fmt) const {
+ parseInt(text, number, -1, pos, allowNegative,fmt);
+}
+
+/**
+ * Parse an integer using fNumberFormat up to maxDigits.
+ */
+void SimpleDateFormat::parseInt(const UnicodeString& text,
+ Formattable& number,
+ int32_t maxDigits,
+ ParsePosition& pos,
+ UBool allowNegative,
+ NumberFormat *fmt) const {
+ UnicodeString oldPrefix;
+ DecimalFormat* df = NULL;
+ if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
+ df->getNegativePrefix(oldPrefix);
+ df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
+ }
+ int32_t oldPos = pos.getIndex();
+ fmt->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,
+ UnicodeString(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,
+ UnicodeString(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)
+}
+
+
+//----------------------------------------------------------------------
+
+
+UBool
+SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
+ return isFieldUnitIgnored(fPattern, field);
+}
+
+
+UBool
+SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
+ UCalendarDateFields field) {
+ int32_t fieldLevel = fgCalendarFieldToLevel[field];
+ int32_t level;
+ UChar ch;
+ UBool inQuote = FALSE;
+ UChar prevCh = 0;
+ int32_t count = 0;
+
+ for (int32_t i = 0; i < pattern.length(); ++i) {
+ ch = pattern[i];
+ if (ch != prevCh && count > 0) {
+ level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE];
+ // the larger the level, the smaller the field unit.
+ if ( fieldLevel <= level ) {
+ return FALSE;
+ }
+ count = 0;
+ }
+ if (ch == QUOTE) {
+ if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) {
+ ++i;
+ } else {
+ inQuote = ! inQuote;
+ }
+ }
+ else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
+ || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
+ prevCh = ch;
+ ++count;
+ }
+ }
+ if ( count > 0 ) {
+ // last item
+ level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE];
+ if ( fieldLevel <= level ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+//----------------------------------------------------------------------
+
+const Locale&
+SimpleDateFormat::getSmpFmtLocale(void) const {
+ return fLocale;
+}
+
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
+ int32_t patLoc, UBool isNegative) const {
+ // local variables
+ UnicodeString suf;
+ int32_t patternMatch;
+ int32_t textPreMatch;
+ int32_t textPostMatch;
+
+ // check that we are still in range
+ if ( (start > text.length()) ||
+ (start < 0) ||
+ (patLoc < 0) ||
+ (patLoc > fPattern.length())) {
+ // out of range, don't advance location in text
+ return start;
+ }
+
+ // get the suffix
+ DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
+ if (decfmt != NULL) {
+ if (isNegative) {
+ suf = decfmt->getNegativeSuffix(suf);
+ }
+ else {
+ suf = decfmt->getPositiveSuffix(suf);
+ }
+ }
+
+ // check for suffix
+ if (suf.length() <= 0) {
+ return start;
+ }
+
+ // check suffix will be encountered in the pattern
+ patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
+
+ // check if a suffix will be encountered in the text
+ textPreMatch = compareSimpleAffix(suf,text,start);
+
+ // check if a suffix was encountered in the text
+ textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
+
+ // check for suffix match
+ if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
+ return start;
+ }
+ else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
+ return start - suf.length();
+ }
+
+ // should not get here
+ return start;
+}
+
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
+ const UnicodeString& input,
+ int32_t pos) const {
+ int32_t start = pos;
+ for (int32_t i=0; i<affix.length(); ) {
+ UChar32 c = affix.char32At(i);
+ int32_t len = U16_LENGTH(c);
+ if (PatternProps::isWhiteSpace(c)) {
+ // We may have a pattern like: \u200F \u0020
+ // and input text like: \u200F \u0020
+ // Note that U+200F and U+0020 are Pattern_White_Space but only
+ // U+0020 is UWhiteSpace. So we have to first do a direct
+ // match of the run of Pattern_White_Space 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 (!PatternProps::isWhiteSpace(c)) {
+ break;
+ }
+ }
+
+ // Advance over run in pattern
+ i = skipPatternWhiteSpace(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;
+ }
+
+ // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
+ // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
+ // is also in the affix.
+ i = skipUWhiteSpace(affix, i);
+ } else {
+ if (pos < input.length() &&
+ input.char32At(pos) == c) {
+ i += len;
+ pos += len;
+ } else {
+ return -1;
+ }
+ }
+ }
+ return pos - start;
+}
+
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
+ const UChar* s = text.getBuffer();
+ return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
+}
+
+//----------------------------------------------------------------------
+
+int32_t
+SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!u_isUWhiteSpace(c)) {
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+//----------------------------------------------------------------------
+
+// Lazy TimeZoneFormat instantiation, semantically const.
+TimeZoneFormat *
+SimpleDateFormat::tzFormat() const {
+ if (fTimeZoneFormat == NULL) {
+ umtx_lock(&LOCK);
+ {
+ if (fTimeZoneFormat == NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
+ U_ASSERT(U_SUCCESS(status));
+
+ const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
+ }
+ }
+ umtx_unlock(&LOCK);
+ }
+ return fTimeZoneFormat;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.cpp
new file mode 100644
index 00000000000..2e138b84fb8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.cpp
@@ -0,0 +1,158 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* This file contains the class SimpleDateFormatStaticSets
+*
+* SimpleDateFormatStaticSets holds the UnicodeSets that are needed for lenient
+* parsing of literal characters in date/time strings.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uniset.h"
+#include "unicode/udat.h"
+#include "cmemory.h"
+#include "ucln_in.h"
+#include "umutex.h"
+
+
+#include "smpdtfst.h"
+
+U_NAMESPACE_BEGIN
+
+SimpleDateFormatStaticSets *SimpleDateFormatStaticSets::gStaticSets = NULL;
+
+SimpleDateFormatStaticSets::SimpleDateFormatStaticSets(UErrorCode *status)
+: fDateIgnorables(NULL),
+ fTimeIgnorables(NULL),
+ fOtherIgnorables(NULL)
+{
+ fDateIgnorables = new UnicodeSet(UNICODE_STRING("[-,./[:whitespace:]]", 20), *status);
+ fTimeIgnorables = new UnicodeSet(UNICODE_STRING("[-.:[:whitespace:]]", 19), *status);
+ fOtherIgnorables = new UnicodeSet(UNICODE_STRING("[:whitespace:]", 14), *status);
+
+ // Check for null pointers
+ if (fDateIgnorables == NULL || fTimeIgnorables == NULL || fOtherIgnorables == NULL) {
+ goto ExitConstrDeleteAll;
+ }
+
+ // Freeze all the sets
+ fDateIgnorables->freeze();
+ fTimeIgnorables->freeze();
+ fOtherIgnorables->freeze();
+
+ return; // If we reached this point, everything is fine so just exit
+
+ExitConstrDeleteAll: // Remove all sets and return error
+ delete fDateIgnorables; fDateIgnorables = NULL;
+ delete fTimeIgnorables; fTimeIgnorables = NULL;
+ delete fOtherIgnorables; fOtherIgnorables = NULL;
+
+ *status = U_MEMORY_ALLOCATION_ERROR;
+}
+
+
+SimpleDateFormatStaticSets::~SimpleDateFormatStaticSets() {
+ delete fDateIgnorables; fDateIgnorables = NULL;
+ delete fTimeIgnorables; fTimeIgnorables = NULL;
+ delete fOtherIgnorables; fOtherIgnorables = NULL;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// smpdtfmt_cleanup Memory cleanup function, free/delete all
+// cached memory. Called by ICU's u_cleanup() function.
+//
+//------------------------------------------------------------------------------
+UBool
+SimpleDateFormatStaticSets::cleanup(void)
+{
+ delete SimpleDateFormatStaticSets::gStaticSets;
+ SimpleDateFormatStaticSets::gStaticSets = NULL;
+
+ return TRUE;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+smpdtfmt_cleanup(void)
+{
+ return SimpleDateFormatStaticSets::cleanup();
+}
+U_CDECL_END
+
+void SimpleDateFormatStaticSets::initSets(UErrorCode *status)
+{
+ SimpleDateFormatStaticSets *p;
+
+ UMTX_CHECK(NULL, gStaticSets, p);
+ if (p == NULL) {
+ p = new SimpleDateFormatStaticSets(status);
+
+ if (p == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ if (U_FAILURE(*status)) {
+ delete p;
+ return;
+ }
+
+ umtx_lock(NULL);
+ if (gStaticSets == NULL) {
+ gStaticSets = p;
+ p = NULL;
+ }
+
+ umtx_unlock(NULL);
+ if (p != NULL) {
+ delete p;
+ }
+
+ ucln_i18n_registerCleanup(UCLN_I18N_SMPDTFMT, smpdtfmt_cleanup);
+ }
+}
+
+UnicodeSet *SimpleDateFormatStaticSets::getIgnorables(UDateFormatField fieldIndex)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ initSets(&status);
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ switch (fieldIndex) {
+ case UDAT_YEAR_FIELD:
+ case UDAT_MONTH_FIELD:
+ case UDAT_DATE_FIELD:
+ case UDAT_STANDALONE_DAY_FIELD:
+ case UDAT_STANDALONE_MONTH_FIELD:
+ return gStaticSets->fDateIgnorables;
+
+ case UDAT_HOUR_OF_DAY1_FIELD:
+ case UDAT_HOUR_OF_DAY0_FIELD:
+ case UDAT_MINUTE_FIELD:
+ case UDAT_SECOND_FIELD:
+ case UDAT_HOUR1_FIELD:
+ case UDAT_HOUR0_FIELD:
+ return gStaticSets->fTimeIgnorables;
+
+ default:
+ return gStaticSets->fOtherIgnorables;
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.h b/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.h
new file mode 100644
index 00000000000..48a2c6cdc26
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/smpdtfst.h
@@ -0,0 +1,52 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* This file contains declarations for the class SimpleDateFormatStaticSets
+*
+* SimpleDateFormatStaticSets holds the UnicodeSets that are needed for lenient
+* parsing of literal characters in date/time strings.
+********************************************************************************
+*/
+
+#ifndef SMPDTFST_H
+#define SMPDTFST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udat.h"
+
+U_NAMESPACE_BEGIN
+
+class UnicodeSet;
+
+
+class SimpleDateFormatStaticSets : public UMemory
+{
+public:
+ static SimpleDateFormatStaticSets *gStaticSets; // Ptr to all lazily initialized constant
+ // shared sets.
+
+ SimpleDateFormatStaticSets(UErrorCode *status);
+ ~SimpleDateFormatStaticSets();
+
+ static void initSets(UErrorCode *status);
+ static UBool cleanup();
+
+ static UnicodeSet *getIgnorables(UDateFormatField fieldIndex);
+
+private:
+ UnicodeSet *fDateIgnorables;
+ UnicodeSet *fTimeIgnorables;
+ UnicodeSet *fOtherIgnorables;
+};
+
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_FORMATTING
+#endif // SMPDTFST_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/sortkey.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/sortkey.cpp
new file mode 100644
index 00000000000..bb4ee8192d2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/sortkey.cpp
@@ -0,0 +1,407 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2011, 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 capacity, int32_t count) {
+ if(fBytes != NULL) {
+ uprv_free(fBytes);
+ }
+ fBytes = values;
+ fCapacity = capacity;
+ setLength(count);
+}
+
+void CollationKey::setLength(int32_t newLength) {
+ fBogus = FALSE;
+ fCount = newLength;
+ 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-4.8.1/i18n/strmatch.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/strmatch.cpp
new file mode 100644
index 00000000000..8286c7eaa07
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/strmatch.h b/Build/source/libs/icu/icu-4.8.1/i18n/strmatch.h
new file mode 100644
index 00000000000..c0d647a194c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/strmatch.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2001-2011, 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.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ 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-4.8.1/i18n/strrepl.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/strrepl.cpp
new file mode 100644
index 00000000000..4ae12b05c24
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/strrepl.h b/Build/source/libs/icu/icu-4.8.1/i18n/strrepl.h
new file mode 100644
index 00000000000..faf96b62962
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/strrepl.h
@@ -0,0 +1,161 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2011, 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.
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/stsearch.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/stsearch.cpp
new file mode 100644
index 00000000000..447f95f3b34
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/stsearch.cpp
@@ -0,0 +1,509 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2008 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 03/22/2000 helena Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#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);
+ // Check null pointer
+ if (m_strsrch_ != NULL) {
+ // 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 0
+ if (position + m_strsrch_->pattern.defaultShiftSize
+ > m_search_->textLength) {
+ setMatchNotFound();
+ return USEARCH_DONE;
+ }
+#endif
+ 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);
+
+#if 0
+ 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;
+ }
+ }
+#else
+ // if m_strsrch_->breakIter is always the same as m_breakiterator_
+ // then we don't need to check the match boundaries here because
+ // usearch_handleNextXXX will already have done it.
+ if (m_search_->isCanonicalMatch) {
+ // *could* actually use exact here 'cause no extra accents allowed...
+ usearch_handleNextCanonical(m_strsrch_, &status);
+ } else {
+ usearch_handleNextExact(m_strsrch_, &status);
+ }
+
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+
+ 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;
+#endif
+ }
+ }
+ 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 0
+ 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;
+ }
+ }
+#else
+ ucol_setOffset(m_strsrch_->textIter, position, &status);
+
+ if (m_search_->isCanonicalMatch) {
+ // *could* use exact match here since extra accents *not* allowed!
+ usearch_handlePreviousCanonical(m_strsrch_, &status);
+ } else {
+ usearch_handlePreviousExact(m_strsrch_, &status);
+ }
+
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+
+ return m_search_->matchedIndex;
+#endif
+ }
+
+ return m_search_->matchedIndex;
+ }
+ return USEARCH_DONE;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/taiwncal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/taiwncal.cpp
new file mode 100644
index 00000000000..4a895251df7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/taiwncal.cpp
@@ -0,0 +1,220 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2003-2008, 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
+ * 05/12/2008 jce modified to use calendar=roc per CLDR
+ *
+ */
+
+#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 "roc";
+}
+
+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.
+ UErrorCode status = U_ZERO_ERROR;
+ TaiwanCalendar calendar(Locale("@calendar=roc"),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);
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ fgSystemDefaultCenturyStartYear = newYear;
+ fgSystemDefaultCenturyStart = newStart;
+ }
+ 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-4.8.1/i18n/taiwncal.h b/Build/source/libs/icu/icu-4.8.1/i18n/taiwncal.h
new file mode 100644
index 00000000000..fe6f89b1902
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/tblcoll.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tblcoll.cpp
new file mode 100644
index 00000000000..e2e62b4fcef
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tblcoll.cpp
@@ -0,0 +1,767 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2011, 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 <typeinfo> // for 'typeid' to work
+
+#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 (typeid(*this) != typeid(that))
+ 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;
+ }
+}
+
+UCollationResult RuleBasedCollator::compare(UCharIterator &sIter,
+ UCharIterator &tIter,
+ UErrorCode &status) const {
+ if(U_SUCCESS(status)) {
+ return ucol_strcollIter(ucollator, &sIter, &tIter, &status);
+ } 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 (sourceLen < -1 || (source == NULL && sourceLen != 0)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return sortkey.setToBogus();
+ }
+
+ if (sourceLen < 0) {
+ sourceLen = u_strlen(source);
+ }
+ if (sourceLen == 0) {
+ return sortkey.reset();
+ }
+
+ uint8_t *result;
+ int32_t resultCapacity;
+ if (sortkey.fCapacity >= (sourceLen * 3)) {
+ // Try to reuse the CollationKey.fBytes.
+ result = sortkey.fBytes;
+ resultCapacity = sortkey.fCapacity;
+ } else {
+ result = NULL;
+ resultCapacity = 0;
+ }
+ int32_t resultLen = ucol_getSortKeyWithAllocation(ucollator, source, sourceLen,
+ result, resultCapacity, &status);
+
+ if (U_SUCCESS(status)) {
+ if (result == sortkey.fBytes) {
+ sortkey.setLength(resultLen);
+ } else {
+ sortkey.adopt(result, resultCapacity, resultLen);
+ }
+ } else {
+ if (result != sortkey.fBytes) {
+ uprv_free(result);
+ }
+ sortkey.setToBogus();
+ }
+ 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();
+ // Null pointer check
+ if (result != NULL) {
+ 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);
+}
+
+int32_t RuleBasedCollator::getReorderCodes(int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode& status) const
+{
+ return ucol_getReorderCodes(ucollator, dest, destCapacity, &status);
+}
+
+void RuleBasedCollator::setReorderCodes(const int32_t *reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode& status)
+{
+ checkOwned();
+ ucol_setReorderCodes(ucollator, reorderCodes, reorderCodesLength, &status);
+}
+
+int32_t RuleBasedCollator::getEquivalentReorderCodes(int32_t reorderCode,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode& status)
+{
+ return ucol_getEquivalentReorderCodes(reorderCode, dest, destCapacity, &status);
+}
+
+/**
+* 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_getLocaleByType(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, const Locale& actualLocale) {
+ checkOwned();
+ char* rloc = uprv_strdup(requestedLocale.getName());
+ if (rloc) {
+ char* vloc = uprv_strdup(validLocale.getName());
+ if (vloc) {
+ char* aloc = uprv_strdup(actualLocale.getName());
+ if (aloc) {
+ ucol_setReqValidLocales(ucollator, rloc, vloc, aloc);
+ return;
+ }
+ uprv_free(vloc);
+ }
+ 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-4.8.1/i18n/timezone.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/timezone.cpp
new file mode 100644
index 00000000000..a70d19ab35a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/timezone.cpp
@@ -0,0 +1,1608 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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 <typeinfo> // for 'typeid' to work
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "ustr_imp.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"
+#include "zonemeta.h"
+
+#define kZONEINFO "zoneinfo64"
+#define kREGIONS "Regions"
+#define kZONES "Zones"
+#define kRULES "Rules"
+#define kNAMES "Names"
+#define kTZVERSION "TZVersion"
+#define kLINKS "links"
+#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
+#define COLON 0x003A
+
+// Static data and constants
+
+static const UChar WORLD[] = {0x30, 0x30, 0x31, 0x00}; /* "001" */
+
+static const UChar GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */
+static const UChar UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00}; /* "Etc/Unknown" */
+static const UChar Z_STR[] = {0x7A, 0x00}; /* "z" */
+static const UChar ZZZZ_STR[] = {0x7A, 0x7A, 0x7A, 0x7A, 0x00}; /* "zzzz" */
+static const UChar Z_UC_STR[] = {0x5A, 0x00}; /* "Z" */
+static const UChar ZZZZ_UC_STR[] = {0x5A, 0x5A, 0x5A, 0x5A, 0x00}; /* "ZZZZ" */
+static const UChar V_STR[] = {0x76, 0x00}; /* "v" */
+static const UChar VVVV_STR[] = {0x76, 0x76, 0x76, 0x76, 0x00}; /* "vvvv" */
+static const UChar V_UC_STR[] = {0x56, 0x00}; /* "V" */
+static const UChar VVVV_UC_STR[] = {0x56, 0x56, 0x56, 0x56, 0x00}; /* "VVVV" */
+static const int32_t GMT_ID_LENGTH = 3;
+static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11;
+
+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];
+static UBool TZDataVersionInitialized = FALSE;
+
+static int32_t* MAP_SYSTEM_ZONES = NULL;
+static int32_t* MAP_CANONICAL_SYSTEM_ZONES = NULL;
+static int32_t* MAP_CANONICAL_SYSTEM_LOCATION_ZONES = NULL;
+
+int32_t LEN_SYSTEM_ZONES = 0;
+int32_t LEN_CANONICAL_SYSTEM_ZONES = 0;
+int32_t LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV timeZone_cleanup(void)
+{
+ delete DEFAULT_ZONE;
+ DEFAULT_ZONE = NULL;
+
+ delete _GMT;
+ _GMT = NULL;
+
+ uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION));
+ TZDataVersionInitialized = FALSE;
+
+ LEN_SYSTEM_ZONES = 0;
+ uprv_free(MAP_SYSTEM_ZONES);
+ MAP_SYSTEM_ZONES = 0;
+
+ LEN_CANONICAL_SYSTEM_ZONES = 0;
+ uprv_free(MAP_CANONICAL_SYSTEM_ZONES);
+ MAP_CANONICAL_SYSTEM_ZONES = 0;
+
+ LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
+ uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES);
+ MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
+
+ 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
+
+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_getType(&res) == URES_INT) {
+ 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;
+}
+
+// -------------------------------------
+
+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) {
+ SimpleTimeZone *tmpGMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
+ umtx_lock(&LOCK);
+ if (_GMT == 0) {
+ _GMT = tmpGMT;
+ tmpGMT = NULL;
+ }
+ umtx_unlock(&LOCK);
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ delete tmpGMT;
+ }
+ 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 typeid(*this) == typeid(that) &&
+ 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 Etc/Unknown(GMT)"));
+ result = new SimpleTimeZone(0, UNKNOWN_ZONE_ID);
+ }
+ 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) {
+ UErrorCode ec = U_ZERO_ERROR;
+ return createSystemTimeZone(id, ec);
+}
+
+TimeZone*
+TimeZone::createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+ TimeZone* z = 0;
+ 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, id, ec);
+ if (z == NULL) {
+ 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);
+
+#ifdef U_WINDOWS
+ // hostID points to a heap-allocated location on Windows.
+ uprv_free(const_cast<char *>(hostID));
+#endif
+
+ 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;
+ }
+
+ // 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) {
+ const TimeZone* temptz = getGMT();
+ // If we can't use GMT, get out.
+ if (temptz == NULL) {
+ return;
+ }
+ default_zone = temptz->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_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
+ // if the zone data could not be loaded.
+ int32_t* map;
+ int32_t* localMap;
+ int32_t len;
+ int32_t pos;
+
+ TZEnumeration(int32_t* mapData, int32_t mapLen, UBool adoptMapData) : pos(0) {
+ map = mapData;
+ localMap = adoptMapData ? mapData : NULL;
+ len = mapLen;
+ }
+
+ 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);
+ }
+
+ static int32_t* getMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) {
+ len = 0;
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+ int32_t* m = NULL;
+ switch (type) {
+ case UCAL_ZONE_TYPE_ANY:
+ m = MAP_SYSTEM_ZONES;
+ len = LEN_SYSTEM_ZONES;
+ break;
+ case UCAL_ZONE_TYPE_CANONICAL:
+ m = MAP_CANONICAL_SYSTEM_ZONES;
+ len = LEN_CANONICAL_SYSTEM_ZONES;
+ break;
+ case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
+ m = MAP_CANONICAL_SYSTEM_LOCATION_ZONES;
+ len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES;
+ break;
+ }
+ UBool needsInit = FALSE;
+ UMTX_CHECK(&LOCK, (len == 0), needsInit);
+ if (needsInit) {
+ m = initMap(type, len, ec);
+ }
+ return m;
+ }
+
+ static int32_t* initMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) {
+ len = 0;
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+
+ int32_t *result = NULL;
+
+ UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
+ res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
+ if (U_SUCCESS(ec)) {
+ int32_t size = ures_getSize(res);
+ int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t));
+ if (m == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ int32_t numEntries = 0;
+ for (int32_t i = 0; i < size; i++) {
+ const UChar *id = ures_getStringByIndex(res, i, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (u_strcmp(id, UNKNOWN_ZONE_ID) == 0) {
+ // exclude Etc/Unknown
+ continue;
+ }
+ if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (canonicalID.compare(id, -1) != 0) {
+ // exclude aliases
+ continue;
+ }
+ }
+ if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
+ const UChar *region = TimeZone::getRegion(id, ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (u_strcmp(region, WORLD) == 0) {
+ // exclude non-location ("001")
+ continue;
+ }
+ }
+ m[numEntries++] = i;
+ }
+ if (U_SUCCESS(ec)) {
+ int32_t *tmp = m;
+ m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t));
+ if (m == NULL) {
+ // realloc failed.. use the original one even it has unused
+ // area at the end
+ m = tmp;
+ }
+
+ umtx_lock(&LOCK);
+ {
+ switch(type) {
+ case UCAL_ZONE_TYPE_ANY:
+ if (MAP_SYSTEM_ZONES == NULL) {
+ MAP_SYSTEM_ZONES = m;
+ LEN_SYSTEM_ZONES = numEntries;
+ m = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ result = MAP_SYSTEM_ZONES;
+ len = LEN_SYSTEM_ZONES;
+ break;
+ case UCAL_ZONE_TYPE_CANONICAL:
+ if (MAP_CANONICAL_SYSTEM_ZONES == NULL) {
+ MAP_CANONICAL_SYSTEM_ZONES = m;
+ LEN_CANONICAL_SYSTEM_ZONES = numEntries;
+ m = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ result = MAP_CANONICAL_SYSTEM_ZONES;
+ len = LEN_CANONICAL_SYSTEM_ZONES;
+ break;
+ case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
+ if (MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL) {
+ MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m;
+ LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries;
+ m = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ result = MAP_CANONICAL_SYSTEM_LOCATION_ZONES;
+ len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES;
+ break;
+ }
+ }
+ umtx_unlock(&LOCK);
+ }
+ uprv_free(m);
+ }
+ }
+
+ ures_close(res);
+ return result;
+ }
+
+public:
+
+#define DEFAULT_FILTERED_MAP_SIZE 8
+#define MAP_INCREMENT_SIZE 8
+
+ static TZEnumeration* create(USystemTimeZoneType type, const char* region, const int32_t* rawOffset, UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+
+ int32_t baseLen;
+ int32_t *baseMap = getMap(type, baseLen, ec);
+
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+
+ // If any additional conditions are available,
+ // create instance local map filtered by the conditions.
+
+ int32_t *filteredMap = NULL;
+ int32_t numEntries = 0;
+
+ if (region != NULL || rawOffset != NULL) {
+ int32_t filteredMapSize = DEFAULT_FILTERED_MAP_SIZE;
+ filteredMap = (int32_t *)uprv_malloc(filteredMapSize * sizeof(int32_t));
+ if (filteredMap == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ // Walk through the base map
+ UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
+ res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
+ for (int32_t i = 0; i < baseLen; i++) {
+ int32_t zidx = baseMap[i];
+ const UChar *id = ures_getStringByIndex(res, zidx, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (region != NULL) {
+ // Filter by region
+ char tzregion[4]; // max 3 letters + null term
+ TimeZone::getRegion(id, tzregion, sizeof(tzregion), ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (uprv_stricmp(tzregion, region) != 0) {
+ // region does not match
+ continue;
+ }
+ }
+ if (rawOffset != NULL) {
+ // Filter by raw offset
+ // Note: This is VERY inefficient
+ TimeZone *z = TimeZone::createSystemTimeZone(id, ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ int32_t tzoffset = z->getRawOffset();
+ delete z;
+
+ if (tzoffset != *rawOffset) {
+ continue;
+ }
+ }
+
+ if (filteredMapSize <= numEntries) {
+ filteredMapSize += MAP_INCREMENT_SIZE;
+ int32_t *tmp = (int32_t *)uprv_realloc(filteredMap, filteredMapSize * sizeof(int32_t));
+ if (tmp == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ } else {
+ filteredMap = tmp;
+ }
+ }
+
+ filteredMap[numEntries++] = zidx;
+ }
+
+ if (U_FAILURE(ec)) {
+ uprv_free(filteredMap);
+ filteredMap = NULL;
+ }
+
+ ures_close(res);
+ }
+
+ TZEnumeration *result = NULL;
+ if (U_SUCCESS(ec)) {
+ // Finally, create a new enumeration instance
+ if (filteredMap == NULL) {
+ result = new TZEnumeration(baseMap, baseLen, FALSE);
+ } else {
+ result = new TZEnumeration(filteredMap, numEntries, TRUE);
+ filteredMap = NULL;
+ }
+ if (result == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+
+ if (filteredMap != NULL) {
+ uprv_free(filteredMap);
+ }
+
+ return result;
+ }
+
+ TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(NULL), localMap(NULL), len(0), pos(0) {
+ if (other.localMap != NULL) {
+ localMap = (int32_t *)uprv_malloc(other.len * sizeof(int32_t));
+ if (localMap != NULL) {
+ len = other.len;
+ uprv_memcpy(localMap, other.localMap, len * sizeof(int32_t));
+ pos = other.pos;
+ map = localMap;
+ } else {
+ len = 0;
+ pos = 0;
+ map = NULL;
+ }
+ } else {
+ map = other.map;
+ localMap = NULL;
+ len = other.len;
+ pos = other.pos;
+ }
+ }
+
+ virtual ~TZEnumeration() {
+ if (localMap != NULL) {
+ uprv_free(localMap);
+ }
+ }
+
+ 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) && map != NULL && pos < len) {
+ getID(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::createTimeZoneIDEnumeration(
+ USystemTimeZoneType zoneType,
+ const char* region,
+ const int32_t* rawOffset,
+ UErrorCode& ec) {
+ return TZEnumeration::create(zoneType, region, rawOffset, ec);
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration() {
+ UErrorCode ec = U_ZERO_ERROR;
+ return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, NULL, NULL, ec);
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration(int32_t rawOffset) {
+ UErrorCode ec = U_ZERO_ERROR;
+ return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, NULL, &rawOffset, ec);
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration(const char* country) {
+ UErrorCode ec = U_ZERO_ERROR;
+ return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, country, NULL, ec);
+}
+
+// ---------------------------------------
+
+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)) {
+ UResourceBundle r;
+ ures_initStackObject(&r);
+ ures_getByKey(&res, kLINKS, &r, &ec);
+ ures_getIntVector(&r, &result, &ec);
+ ures_close(&r);
+ }
+ 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)) {
+ UResourceBundle r;
+ ures_initStackObject(&r);
+ int32_t size;
+ ures_getByKey(&res, kLINKS, &r, &ec);
+ const int32_t* v = ures_getIntVector(&r, &size, &ec);
+ if (U_SUCCESS(ec)) {
+ if (index >= 0 && index < size) {
+ 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;
+}
+
+// ---------------------------------------
+
+// These methods are used by ZoneMeta class only.
+
+const UChar*
+TimeZone::findID(const UnicodeString& id) {
+ const UChar *result = NULL;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
+
+ // resolve zone index by name
+ UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec);
+ int32_t idx = findInStringArray(names, id, ec);
+ result = ures_getStringByIndex(names, idx, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ result = NULL;
+ }
+ ures_close(names);
+ ures_close(rb);
+ return result;
+}
+
+
+const UChar*
+TimeZone::dereferOlsonLink(const UnicodeString& id) {
+ const UChar *result = NULL;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
+
+ // resolve zone index by name
+ UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec);
+ int32_t idx = findInStringArray(names, id, ec);
+ result = ures_getStringByIndex(names, idx, NULL, &ec);
+
+ // open the zone bundle by index
+ ures_getByKey(rb, kZONES, rb, &ec);
+ ures_getByIndex(rb, idx, rb, &ec);
+
+ if (U_SUCCESS(ec)) {
+ if (ures_getType(rb) == URES_INT) {
+ // this is a link - dereference the link
+ int32_t deref = ures_getInt(rb, &ec);
+ const UChar* tmp = ures_getStringByIndex(names, deref, NULL, &ec);
+ if (U_SUCCESS(ec)) {
+ result = tmp;
+ }
+ }
+ }
+
+ ures_close(names);
+ ures_close(rb);
+
+ return result;
+}
+
+const UChar*
+TimeZone::getRegion(const UnicodeString& id) {
+ UErrorCode status = U_ZERO_ERROR;
+ return getRegion(id, status);
+}
+
+const UChar*
+TimeZone::getRegion(const UnicodeString& id, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ const UChar *result = NULL;
+ UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &status);
+
+ // resolve zone index by name
+ UResourceBundle *res = ures_getByKey(rb, kNAMES, NULL, &status);
+ int32_t idx = findInStringArray(res, id, status);
+
+ // get region mapping
+ ures_getByKey(rb, kREGIONS, res, &status);
+ const UChar *tmp = ures_getStringByIndex(res, idx, NULL, &status);
+ if (U_SUCCESS(status)) {
+ result = tmp;
+ }
+
+ ures_close(res);
+ ures_close(rb);
+
+ return result;
+}
+
+
+// ---------------------------------------
+int32_t
+TimeZone::getRegion(const UnicodeString& id, char *region, int32_t capacity, UErrorCode& status)
+{
+ int32_t resultLen = 0;
+ *region = 0;
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ const UChar *uregion = NULL;
+ // "Etc/Unknown" is not a system zone ID,
+ // but in the zone data
+ if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) != 0) {
+ uregion = getRegion(id);
+ }
+ if (uregion == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ resultLen = u_strlen(uregion);
+ // A region code is represented by invariant characters
+ u_UCharsToChars(uregion, region, uprv_min(resultLen, capacity));
+
+ if (capacity < resultLen) {
+ status = U_BUFFER_OVERFLOW_ERROR;
+ return resultLen;
+ }
+
+ return u_terminateChars(region, capacity, resultLen, &status);
+}
+
+// ---------------------------------------
+
+
+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
+
+ // select the proper format string
+ UnicodeString pat;
+ switch(style){
+ case LONG:
+ pat = ZZZZ_STR;
+ break;
+ case SHORT_GENERIC:
+ pat = V_STR;
+ break;
+ case LONG_GENERIC:
+ pat = VVVV_STR;
+ break;
+ case SHORT_GMT:
+ pat = Z_UC_STR;
+ break;
+ case LONG_GMT:
+ pat = ZZZZ_UC_STR;
+ break;
+ case SHORT_COMMONLY_USED:
+ //pat = V_UC_STR;
+ pat = Z_STR;
+ break;
+ case GENERIC_LOCATION:
+ pat = VVVV_UC_STR;
+ break;
+ default: // SHORT
+ //pat = Z_STR;
+ pat = V_UC_STR;
+ break;
+ }
+
+ SimpleDateFormat format(pat, 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();
+ }
+
+ UDate d = Calendar::getNow();
+ int32_t rawOffset;
+ int32_t dstOffset;
+ this->getOffset(d, FALSE, rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ return result.remove();
+ }
+
+ if ((daylight && dstOffset != 0) ||
+ (!daylight && dstOffset == 0) ||
+ (style == SHORT_GENERIC) ||
+ (style == LONG_GENERIC)
+ ) {
+ // Current time and the request (daylight / not daylight) agree.
+ format.setTimeZone(*this);
+ return format.format(d, result);
+ }
+
+ // Create a new SimpleTimeZone as a stand-in for this zone; the
+ // stand-in will have no DST, or DST during July, 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;
+ getID(tempID);
+ SimpleTimeZone *tz = NULL;
+ if(daylight && useDaylightTime()){
+ // The display name for daylight saving time was requested, but currently not in DST
+ // Set a fixed date (July 1) in this Gregorian year
+ GregorianCalendar cal(*this, status);
+ if (U_FAILURE(status)) {
+ return result.remove();
+ }
+ cal.set(UCAL_MONTH, UCAL_JULY);
+ cal.set(UCAL_DATE, 1);
+
+ // Get July 1 date
+ d = cal.getTime(status);
+
+ // Check if it is in DST
+ if (cal.get(UCAL_DST_OFFSET, status) == 0) {
+ // We need to create a fake time zone
+ tz = new SimpleTimeZone(rawOffset, tempID,
+ UCAL_JUNE, 1, 0, 0,
+ UCAL_AUGUST, 1, 0, 0,
+ getDSTSavings(), status);
+ if (U_FAILURE(status) || tz == NULL) {
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result.remove();
+ }
+ format.adoptTimeZone(tz);
+ } else {
+ format.setTimeZone(*this);
+ }
+ } else {
+ // The display name for standard time was requested, but currently in DST
+ // or display name for daylight saving time was requested, but this zone no longer
+ // observes DST.
+ tz = new SimpleTimeZone(rawOffset, tempID);
+ if (U_FAILURE(status) || tz == NULL) {
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result.remove();
+ }
+ format.adoptTimeZone(tz);
+ }
+
+ format.format(d, result, status);
+ return result;
+}
+
+/**
+ * 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)
+{
+ int32_t sign, hour, min, sec;
+ if (parseCustomID(id, sign, hour, min, sec)) {
+ UnicodeString customID;
+ formatCustomID(hour, min, sec, (sign < 0), customID);
+ int32_t offset = sign * ((hour * 60 + min) * 60 + sec) * 1000;
+ return new SimpleTimeZone(offset, customID);
+ }
+ return NULL;
+}
+
+UnicodeString&
+TimeZone::getCustomID(const UnicodeString& id, UnicodeString& normalized, UErrorCode& status) {
+ normalized.remove();
+ if (U_FAILURE(status)) {
+ return normalized;
+ }
+ int32_t sign, hour, min, sec;
+ if (parseCustomID(id, sign, hour, min, sec)) {
+ formatCustomID(hour, min, sec, (sign < 0), normalized);
+ }
+ return normalized;
+}
+
+UBool
+TimeZone::parseCustomID(const UnicodeString& id, int32_t& sign,
+ int32_t& hour, int32_t& min, int32_t& sec) {
+ 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);
+ sign = 1;
+ hour = 0;
+ min = 0;
+ sec = 0;
+
+ if (id[pos.getIndex()] == MINUS /*'-'*/) {
+ sign = -1;
+ } else if (id[pos.getIndex()] != PLUS /*'+'*/) {
+ return FALSE;
+ }
+ pos.setIndex(pos.getIndex() + 1);
+
+ UErrorCode success = U_ZERO_ERROR;
+ numberFormat = NumberFormat::createInstance(success);
+ if(U_FAILURE(success)){
+ return FALSE;
+ }
+ numberFormat->setParseIntegerOnly(TRUE);
+ //numberFormat->setLenient(TRUE); // TODO: May need to set this, depends on latest timezone parsing
+
+ // 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 FALSE;
+ }
+ hour = n.getLong();
+
+ if (pos.getIndex() < id.length()) {
+ if (pos.getIndex() - start > 2
+ || id[pos.getIndex()] != COLON) {
+ delete numberFormat;
+ return FALSE;
+ }
+ // 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 FALSE;
+ }
+ min = n.getLong();
+ if (pos.getIndex() < id.length()) {
+ if (id[pos.getIndex()] != COLON) {
+ delete numberFormat;
+ return FALSE;
+ }
+ // [: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 FALSE;
+ }
+ 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 FALSE;
+ }
+ 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 FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UnicodeString&
+TimeZone::formatCustomID(int32_t hour, int32_t min, int32_t sec,
+ UBool negative, UnicodeString& id) {
+ // Create time zone ID - GMT[+|-]hhmm[ss]
+ id.setTo(GMT_ID);
+ if (hour | min | sec) {
+ if (negative) {
+ id += (UChar)MINUS;
+ } else {
+ id += (UChar)PLUS;
+ }
+
+ if (hour < 10) {
+ id += (UChar)ZERO_DIGIT;
+ } else {
+ id += (UChar)(ZERO_DIGIT + hour/10);
+ }
+ id += (UChar)(ZERO_DIGIT + hour%10);
+ id += (UChar)COLON;
+ if (min < 10) {
+ id += (UChar)ZERO_DIGIT;
+ } else {
+ id += (UChar)(ZERO_DIGIT + min/10);
+ }
+ id += (UChar)(ZERO_DIGIT + min%10);
+
+ if (sec) {
+ id += (UChar)COLON;
+ if (sec < 10) {
+ id += (UChar)ZERO_DIGIT;
+ } else {
+ id += (UChar)(ZERO_DIGIT + sec/10);
+ }
+ id += (UChar)(ZERO_DIGIT + sec%10);
+ }
+ }
+ return id;
+}
+
+
+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, !TZDataVersionInitialized, needsInit);
+ if (needsInit) {
+ int32_t len = 0;
+ UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status);
+ const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION,
+ &len, &status);
+
+ if (U_SUCCESS(status)) {
+ if (len >= (int32_t)sizeof(TZDATA_VERSION)) {
+ // Ensure that there is always space for a trailing nul in TZDATA_VERSION
+ len = sizeof(TZDATA_VERSION) - 1;
+ }
+ umtx_lock(&LOCK);
+ if (!TZDataVersionInitialized) {
+ u_UCharsToChars(tzver, TZDATA_VERSION, len);
+ TZDataVersionInitialized = TRUE;
+ }
+ umtx_unlock(&LOCK);
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+
+ ures_close(bundle);
+ }
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ return (const char*)TZDATA_VERSION;
+}
+
+UnicodeString&
+TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UErrorCode& status)
+{
+ UBool isSystemID = FALSE;
+ return getCanonicalID(id, canonicalID, isSystemID, status);
+}
+
+UnicodeString&
+TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UBool& isSystemID,
+ UErrorCode& status)
+{
+ canonicalID.remove();
+ isSystemID = FALSE;
+ if (U_FAILURE(status)) {
+ return canonicalID;
+ }
+ if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) == 0) {
+ // special case - Etc/Unknown is a canonical ID, but not system ID
+ canonicalID.fastCopyFrom(id);
+ isSystemID = FALSE;
+ } else {
+ ZoneMeta::getCanonicalCLDRID(id, canonicalID, status);
+ if (U_SUCCESS(status)) {
+ isSystemID = TRUE;
+ } else {
+ // Not a system ID
+ status = U_ZERO_ERROR;
+ getCustomID(id, canonicalID, status);
+ }
+ }
+ return canonicalID;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/titletrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/titletrn.cpp
new file mode 100644
index 00000000000..76c17d1bad7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/titletrn.h b/Build/source/libs/icu/icu-4.8.1/i18n/titletrn.h
new file mode 100644
index 00000000000..a093152b66c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/tmunit.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tmunit.cpp
new file mode 100644
index 00000000000..fb31e252091
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tmunit.cpp
@@ -0,0 +1,117 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2010, Google, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#include <typeinfo> // for 'typeid' to work
+
+#include "unicode/tmunit.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnit)
+
+
+/*
+ * There are only 7 time units.
+ * So, TimeUnit could be made as singleton
+ * (similar to uniset_props.cpp, or unorm.cpp,
+ * in which a static TimeUnit* array is created, and
+ * the creatInstance() returns a const TimeUnit*).
+ * But the constraint is TimeUnit is a data member of Measure.
+ * But Measure (which is an existing API) does not expect it's "unit" member
+ * as singleton. Meaure takes ownership of the "unit" member.
+ * In its constructor, it does not take a const "unit" pointer.
+ * Also, Measure can clone and destruct the "unit" pointer.
+ * In order to preserve the old behavior and let Measure handle singleton "unit",
+ * 1. a flag need to be added in Measure;
+ * 2. a new constructor which takes const "unit" as parameter need to be added,
+ * and this new constructor will set the flag on.
+ * 3. clone and destructor need to check upon this flag to distinguish on how
+ * to handle the "unit".
+ *
+ * Since TimeUnit is such a light weight object, comparing with the heavy weight
+ * format operation, we decided to avoid the above complication.
+ *
+ * So, both TimeUnit and CurrencyUnit (the 2 subclasses of MeasureUnit) are
+ * immutable and non-singleton.
+ *
+ * Currently, TimeUnitAmount and CurrencyAmount are immutable.
+ * If an application needs to create a long list of TimeUnitAmount on the same
+ * time unit but different number, for example,
+ * 1 hour, 2 hour, 3 hour, ................. 10,000 hour,
+ * there might be performance hit because 10,000 TimeUnit object,
+ * although all are the same time unit, will be created in heap and deleted.
+ *
+ * To address this performance issue, if there is any in the future,
+ * we should and need to change TimeUnitAmount and CurrencyAmount to be
+ * immutable by allowing a setter on the number.
+ * Or we need to add 2 parallel mutable classes in order to
+ * preserve the existing API.
+ * Or we can use freezable.
+ */
+TimeUnit* U_EXPORT2
+TimeUnit::createInstance(TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (timeUnitField < 0 || timeUnitField >= UTIMEUNIT_FIELD_COUNT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ return new TimeUnit(timeUnitField);
+}
+
+
+TimeUnit::TimeUnit(TimeUnit::UTimeUnitFields timeUnitField) {
+ fTimeUnitField = timeUnitField;
+}
+
+
+TimeUnit::TimeUnit(const TimeUnit& other)
+: MeasureUnit(other) {
+ *this = other;
+}
+
+
+UObject*
+TimeUnit::clone() const {
+ return new TimeUnit(*this);
+}
+
+
+TimeUnit&
+TimeUnit::operator=(const TimeUnit& other) {
+ if (this == &other) {
+ return *this;
+ }
+ fTimeUnitField = other.fTimeUnitField;
+ return *this;
+}
+
+
+UBool
+TimeUnit::operator==(const UObject& other) const {
+ return (typeid(*this) == typeid(other)
+ && fTimeUnitField == ((TimeUnit*)&other)->fTimeUnitField);
+}
+
+
+TimeUnit::UTimeUnitFields
+TimeUnit::getTimeUnitField() const {
+ return fTimeUnitField;
+}
+
+
+TimeUnit::~TimeUnit() {
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tmutamt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tmutamt.cpp
new file mode 100644
index 00000000000..382c7ffd292
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tmutamt.cpp
@@ -0,0 +1,76 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/tmutamt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitAmount)
+
+
+TimeUnitAmount::TimeUnitAmount(const Formattable& number,
+ TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status)
+: Measure(number, TimeUnit::createInstance(timeUnitField, status), status) {
+}
+
+
+TimeUnitAmount::TimeUnitAmount(double amount,
+ TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status)
+: Measure(Formattable(amount),
+ TimeUnit::createInstance(timeUnitField, status),
+ status) {
+}
+
+
+TimeUnitAmount::TimeUnitAmount(const TimeUnitAmount& other)
+: Measure(other)
+{
+}
+
+
+TimeUnitAmount&
+TimeUnitAmount::operator=(const TimeUnitAmount& other) {
+ Measure::operator=(other);
+ return *this;
+}
+
+
+UBool
+TimeUnitAmount::operator==(const UObject& other) const {
+ return Measure::operator==(other);
+}
+
+UObject*
+TimeUnitAmount::clone() const {
+ return new TimeUnitAmount(*this);
+}
+
+
+TimeUnitAmount::~TimeUnitAmount() {
+}
+
+
+
+const TimeUnit&
+TimeUnitAmount::getTimeUnit() const {
+ return (const TimeUnit&) getUnit();
+}
+
+
+TimeUnit::UTimeUnitFields
+TimeUnitAmount::getTimeUnitField() const {
+ return getTimeUnit().getTimeUnitField();
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tmutfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tmutfmt.cpp
new file mode 100644
index 00000000000..9a40fc427d5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tmutfmt.cpp
@@ -0,0 +1,885 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2011, Google, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#include <typeinfo> // for 'typeid' to work
+
+#include "unicode/tmutfmt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "unicode/msgfmt.h"
+
+#define LEFT_CURLY_BRACKET ((UChar)0x007B)
+#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
+#define SPACE ((UChar)0x0020)
+#define DIGIT_ZERO ((UChar)0x0030)
+#define LOW_S ((UChar)0x0073)
+#define LOW_M ((UChar)0x006D)
+#define LOW_I ((UChar)0x0069)
+#define LOW_N ((UChar)0x006E)
+#define LOW_H ((UChar)0x0068)
+#define LOW_W ((UChar)0x0077)
+#define LOW_D ((UChar)0x0064)
+#define LOW_Y ((UChar)0x0079)
+#define LOW_Z ((UChar)0x007A)
+#define LOW_E ((UChar)0x0065)
+#define LOW_R ((UChar)0x0072)
+#define LOW_O ((UChar)0x006F)
+#define LOW_N ((UChar)0x006E)
+#define LOW_T ((UChar)0x0074)
+
+
+//TODO: define in compile time
+//#define TMUTFMT_DEBUG 1
+
+#ifdef TMUTFMT_DEBUG
+#include <iostream>
+#endif
+
+U_NAMESPACE_BEGIN
+
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat)
+
+static const char gUnitsTag[] = "units";
+static const char gShortUnitsTag[] = "unitsShort";
+static const char gTimeUnitYear[] = "year";
+static const char gTimeUnitMonth[] = "month";
+static const char gTimeUnitDay[] = "day";
+static const char gTimeUnitWeek[] = "week";
+static const char gTimeUnitHour[] = "hour";
+static const char gTimeUnitMinute[] = "minute";
+static const char gTimeUnitSecond[] = "second";
+static const char gPluralCountOther[] = "other";
+
+static const UChar DEFAULT_PATTERN_FOR_SECOND[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_S, 0};
+static const UChar DEFAULT_PATTERN_FOR_MINUTE[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, LOW_I, LOW_N, 0};
+static const UChar DEFAULT_PATTERN_FOR_HOUR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_H, 0};
+static const UChar DEFAULT_PATTERN_FOR_WEEK[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_W, 0};
+static const UChar DEFAULT_PATTERN_FOR_DAY[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_D, 0};
+static const UChar DEFAULT_PATTERN_FOR_MONTH[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, 0};
+static const UChar DEFAULT_PATTERN_FOR_YEAR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_Y, 0};
+
+static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
+static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
+static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
+
+
+TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(Locale::getDefault(), UTMUTFMT_FULL_STYLE, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(locale, UTMUTFMT_FULL_STYLE, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(locale, style, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
+: MeasureFormat(other),
+ fNumberFormat(NULL),
+ fPluralRules(NULL),
+ fStyle(UTMUTFMT_FULL_STYLE)
+{
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ *this = other;
+}
+
+
+TimeUnitFormat::~TimeUnitFormat() {
+ delete fNumberFormat;
+ fNumberFormat = NULL;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ deleteHash(fTimeUnitToCountToPatterns[i]);
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ delete fPluralRules;
+ fPluralRules = NULL;
+}
+
+
+Format*
+TimeUnitFormat::clone(void) const {
+ return new TimeUnitFormat(*this);
+}
+
+
+TimeUnitFormat&
+TimeUnitFormat::operator=(const TimeUnitFormat& other) {
+ if (this == &other) {
+ return *this;
+ }
+ delete fNumberFormat;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ deleteHash(fTimeUnitToCountToPatterns[i]);
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ delete fPluralRules;
+ if (other.fNumberFormat) {
+ fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
+ } else {
+ fNumberFormat = NULL;
+ }
+ fLocale = other.fLocale;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ UErrorCode status = U_ZERO_ERROR;
+ fTimeUnitToCountToPatterns[i] = initHash(status);
+ if (U_SUCCESS(status)) {
+ copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
+ } else {
+ delete fTimeUnitToCountToPatterns[i];
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ }
+ if (other.fPluralRules) {
+ fPluralRules = (PluralRules*)other.fPluralRules->clone();
+ } else {
+ fPluralRules = NULL;
+ }
+ fStyle = other.fStyle;
+ return *this;
+}
+
+
+UBool
+TimeUnitFormat::operator==(const Format& other) const {
+ if (typeid(*this) == typeid(other)) {
+ TimeUnitFormat* fmt = (TimeUnitFormat*)&other;
+ UBool ret = ( ((fNumberFormat && fmt->fNumberFormat && *fNumberFormat == *fmt->fNumberFormat)
+ || fNumberFormat == fmt->fNumberFormat )
+ && fLocale == fmt->fLocale
+ && ((fPluralRules && fmt->fPluralRules && *fPluralRules == *fmt->fPluralRules)
+ || fPluralRules == fmt->fPluralRules)
+ && fStyle == fmt->fStyle);
+ if (ret) {
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i]));
+ }
+ }
+ return ret;
+ }
+ return false;
+}
+
+
+UnicodeString&
+TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
+ FieldPosition& pos, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return toAppendTo;
+ }
+ if (obj.getType() == Formattable::kObject) {
+ const UObject* formatObj = obj.getObject();
+ const TimeUnitAmount* amount = dynamic_cast<const TimeUnitAmount*>(formatObj);
+ if (amount != NULL){
+ Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
+ double number;
+ const Formattable& amtNumber = amount->getNumber();
+ if (amtNumber.getType() == Formattable::kDouble) {
+ number = amtNumber.getDouble();
+ } else if (amtNumber.getType() == Formattable::kLong) {
+ number = amtNumber.getLong();
+ } else {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return toAppendTo;
+ }
+ UnicodeString count = fPluralRules->select(number);
+#ifdef TMUTFMT_DEBUG
+ char result[1000];
+ count.extract(0, count.length(), result, "UTF-8");
+ std::cout << "number: " << number << "; format plural count: " << result << "\n";
+#endif
+ MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
+ Formattable formattable[1];
+ formattable[0].setDouble(number);
+ return pattern->format(formattable, 1, toAppendTo, pos, status);
+ }
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return toAppendTo;
+}
+
+
+void
+TimeUnitFormat::parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const {
+ double resultNumber = -1;
+ UBool withNumberFormat = false;
+ TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ int32_t oldPos = pos.getIndex();
+ int32_t newPos = -1;
+ int32_t longestParseDistance = 0;
+ UnicodeString* countOfLongestMatch = NULL;
+#ifdef TMUTFMT_DEBUG
+ char res[1000];
+ source.extract(0, source.length(), res, "UTF-8");
+ std::cout << "parse source: " << res << "\n";
+#endif
+ // parse by iterating through all available patterns
+ // and looking for the longest match.
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
+ int32_t elemPos = -1;
+ const UHashElement* elem = NULL;
+ while ((elem = countToPatterns->nextElement(elemPos)) != NULL){
+ const UHashTok keyTok = elem->key;
+ UnicodeString* count = (UnicodeString*)keyTok.pointer;
+#ifdef TMUTFMT_DEBUG
+ count->extract(0, count->length(), res, "UTF-8");
+ std::cout << "parse plural count: " << res << "\n";
+#endif
+ const UHashTok valueTok = elem->value;
+ // the value is a pair of MessageFormat*
+ MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
+ for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT;
+ style = (UTimeUnitFormatStyle)(style + 1)) {
+ MessageFormat* pattern = patterns[style];
+ pos.setErrorIndex(-1);
+ pos.setIndex(oldPos);
+ // see if we can parse
+ Formattable parsed;
+ pattern->parseObject(source, parsed, pos);
+ if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) {
+ continue;
+ }
+ #ifdef TMUTFMT_DEBUG
+ std::cout << "parsed.getType: " << parsed.getType() << "\n";
+ #endif
+ double tmpNumber = 0;
+ if (pattern->getArgTypeCount() != 0) {
+ // pattern with Number as beginning, such as "{0} d".
+ // check to make sure that the timeUnit is consistent
+ Formattable& temp = parsed[0];
+ if (temp.getType() == Formattable::kDouble) {
+ tmpNumber = temp.getDouble();
+ } else if (temp.getType() == Formattable::kLong) {
+ tmpNumber = temp.getLong();
+ } else {
+ continue;
+ }
+ UnicodeString select = fPluralRules->select(tmpNumber);
+ #ifdef TMUTFMT_DEBUG
+ select.extract(0, select.length(), res, "UTF-8");
+ std::cout << "parse plural select count: " << res << "\n";
+ #endif
+ if (*count != select) {
+ continue;
+ }
+ }
+ int32_t parseDistance = pos.getIndex() - oldPos;
+ if (parseDistance > longestParseDistance) {
+ if (pattern->getArgTypeCount() != 0) {
+ resultNumber = tmpNumber;
+ withNumberFormat = true;
+ } else {
+ withNumberFormat = false;
+ }
+ resultTimeUnit = i;
+ newPos = pos.getIndex();
+ longestParseDistance = parseDistance;
+ countOfLongestMatch = count;
+ }
+ }
+ }
+ }
+ /* After find the longest match, parse the number.
+ * Result number could be null for the pattern without number pattern.
+ * such as unit pattern in Arabic.
+ * When result number is null, use plural rule to set the number.
+ */
+ if (withNumberFormat == false && longestParseDistance != 0) {
+ // set the number using plurrual count
+ if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) {
+ resultNumber = 0;
+ } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) {
+ resultNumber = 1;
+ } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) {
+ resultNumber = 2;
+ } else {
+ // should not happen.
+ // TODO: how to handle?
+ resultNumber = 3;
+ }
+ }
+ if (longestParseDistance == 0) {
+ pos.setIndex(oldPos);
+ pos.setErrorIndex(0);
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
+ if (U_SUCCESS(status)) {
+ result.adoptObject(tmutamt);
+ pos.setIndex(newPos);
+ pos.setErrorIndex(-1);
+ } else {
+ pos.setIndex(oldPos);
+ pos.setErrorIndex(0);
+ }
+ }
+}
+
+
+void
+TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (style < UTMUTFMT_FULL_STYLE || style > UTMUTFMT_ABBREVIATED_STYLE) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ fStyle = style;
+ fLocale = locale;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ //TODO: format() and parseObj() are const member functions,
+ //so, can not do lazy initialization in C++.
+ //setup has to be done in constructors.
+ //and here, the behavior is not consistent with Java.
+ //In Java, create an empty instance does not setup locale as
+ //default locale. If it followed by setNumberFormat(),
+ //in format(), the locale will set up as the locale in fNumberFormat.
+ //But in C++, this sets the locale as the default locale.
+ setup(status);
+}
+
+void
+TimeUnitFormat::setup(UErrorCode& err) {
+ initDataMembers(err);
+ readFromCurrentLocale(UTMUTFMT_FULL_STYLE, gUnitsTag, err);
+ checkConsistency(UTMUTFMT_FULL_STYLE, gUnitsTag, err);
+ readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err);
+ checkConsistency(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err);
+}
+
+
+void
+TimeUnitFormat::initDataMembers(UErrorCode& err){
+ if (U_FAILURE(err)) {
+ return;
+ }
+ if (fNumberFormat == NULL) {
+ fNumberFormat = NumberFormat::createInstance(fLocale, err);
+ }
+ delete fPluralRules;
+ fPluralRules = PluralRules::forLocale(fLocale, err);
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ deleteHash(fTimeUnitToCountToPatterns[i]);
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+}
+
+
+
+
+void
+TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) {
+ if (U_FAILURE(err)) {
+ return;
+ }
+ // fill timeUnitToCountToPatterns from resource file
+ // err is used to indicate wrong status except missing resource.
+ // status is an error code used in resource lookup.
+ // status does not affect "err".
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *rb, *unitsRes;
+ rb = ures_open(NULL, fLocale.getName(), &status);
+ unitsRes = ures_getByKey(rb, key, NULL, &status);
+ if (U_FAILURE(status)) {
+ ures_close(unitsRes);
+ ures_close(rb);
+ return;
+ }
+ int32_t size = ures_getSize(unitsRes);
+ for ( int32_t index = 0; index < size; ++index) {
+ // resource of one time unit
+ UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index,
+ NULL, &status);
+ if (U_SUCCESS(status)) {
+ const char* timeUnitName = ures_getKey(oneTimeUnit);
+ if (timeUnitName == NULL) {
+ ures_close(oneTimeUnit);
+ continue;
+ }
+ UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes,
+ timeUnitName,
+ NULL, &status);
+ if (countsToPatternRB == NULL || U_FAILURE(status)) {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ continue;
+ }
+ TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_YEAR;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_MONTH;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_DAY;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_HOUR;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_MINUTE;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_SECOND;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_WEEK;
+ } else {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ continue;
+ }
+ Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField];
+ if (countToPatterns == NULL) {
+ countToPatterns = initHash(err);
+ if (U_FAILURE(err)) {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ delete countToPatterns;
+ break;
+ }
+ }
+ int32_t count = ures_getSize(countsToPatternRB);
+ const char* pluralCount;
+ for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
+ // resource of count to pattern
+ UnicodeString pattern =
+ ures_getNextUnicodeString(countsToPatternRB, &pluralCount, &status);
+ if (U_FAILURE(status)) {
+ continue;
+ }
+ MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
+ if ( U_SUCCESS(err) ) {
+ if (fNumberFormat != NULL) {
+ messageFormat->setFormat(0, *fNumberFormat);
+ }
+ UnicodeString pluralCountUniStr(pluralCount, -1, US_INV);
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr);
+ if (formatters == NULL) {
+ formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
+ formatters[UTMUTFMT_FULL_STYLE] = NULL;
+ formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
+ countToPatterns->put(pluralCountUniStr, formatters, err);
+ if (U_FAILURE(err)) {
+ uprv_free(formatters);
+ }
+ }
+ if (U_SUCCESS(err)) {
+ //delete formatters[style];
+ formatters[style] = messageFormat;
+ }
+ }
+ if (U_FAILURE(err)) {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ ures_close(unitsRes);
+ ures_close(rb);
+ delete messageFormat;
+ delete countToPatterns;
+ return;
+ }
+ }
+ if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) {
+ fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns;
+ }
+ ures_close(countsToPatternRB);
+ }
+ ures_close(oneTimeUnit);
+ }
+ ures_close(unitsRes);
+ ures_close(rb);
+}
+
+
+void
+TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) {
+ if (U_FAILURE(err)) {
+ return;
+ }
+ // there should be patterns for each plural rule in each time unit.
+ // For each time unit,
+ // for each plural rule, following is unit pattern fall-back rule:
+ // ( for example: "one" hour )
+ // look for its unit pattern in its locale tree.
+ // if pattern is not found in its own locale, such as de_DE,
+ // look for the pattern in its parent, such as de,
+ // keep looking till found or till root.
+ // if the pattern is not found in root either,
+ // fallback to plural count "other",
+ // look for the pattern of "other" in the locale tree:
+ // "de_DE" to "de" to "root".
+ // If not found, fall back to value of
+ // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
+ //
+ // Following is consistency check to create pattern for each
+ // plural rule in each time unit using above fall-back rule.
+ //
+ StringEnumeration* keywords = fPluralRules->getKeywords(err);
+ if (U_SUCCESS(err)) {
+ const UnicodeString* pluralCount;
+ while ((pluralCount = keywords->snext(err)) != NULL) {
+ if ( U_SUCCESS(err) ) {
+ for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
+ // for each time unit,
+ // get all the patterns for each plural rule in this locale.
+ Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
+ if ( countToPatterns == NULL ) {
+ countToPatterns = initHash(err);
+ if (U_FAILURE(err)) {
+ delete countToPatterns;
+ return;
+ }
+ fTimeUnitToCountToPatterns[i] = countToPatterns;
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount);
+ if( formatters == NULL || formatters[style] == NULL ) {
+ // look through parents
+ const char* localeName = fLocale.getName();
+ CharString pluralCountChars;
+ pluralCountChars.appendInvariantChars(*pluralCount, err);
+ searchInLocaleChain(style, key, localeName,
+ (TimeUnit::UTimeUnitFields)i,
+ *pluralCount, pluralCountChars.data(),
+ countToPatterns, err);
+ }
+ }
+ }
+ }
+ }
+ delete keywords;
+}
+
+
+
+// srcPluralCount is the original plural count on which the pattern is
+// searched for.
+// searchPluralCount is the fallback plural count.
+// For example, to search for pattern for ""one" hour",
+// "one" is the srcPluralCount,
+// if the pattern is not found even in root, fallback to
+// using patterns of plural count "other",
+// then, "other" is the searchPluralCount.
+void
+TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key, const char* localeName,
+ TimeUnit::UTimeUnitFields srcTimeUnitField,
+ const UnicodeString& srcPluralCount,
+ const char* searchPluralCount,
+ Hashtable* countToPatterns,
+ UErrorCode& err) {
+ if (U_FAILURE(err)) {
+ return;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ char parentLocale[ULOC_FULLNAME_CAPACITY];
+ uprv_strcpy(parentLocale, localeName);
+ int32_t locNameLen;
+ while ((locNameLen = uloc_getParent(parentLocale, parentLocale,
+ ULOC_FULLNAME_CAPACITY, &status)) >= 0){
+ // look for pattern for srcPluralCount in locale tree
+ UResourceBundle *rb, *unitsRes, *countsToPatternRB;
+ rb = ures_open(NULL, parentLocale, &status);
+ unitsRes = ures_getByKey(rb, key, NULL, &status);
+ const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
+ countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
+ const UChar* pattern;
+ int32_t ptLength;
+ pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
+ if (U_SUCCESS(status)) {
+ //found
+ MessageFormat* messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, ptLength), fLocale, err);
+ if (U_SUCCESS(err)) {
+ if (fNumberFormat != NULL) {
+ messageFormat->setFormat(0, *fNumberFormat);
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
+ if (formatters == NULL) {
+ formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
+ formatters[UTMUTFMT_FULL_STYLE] = NULL;
+ formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
+ countToPatterns->put(srcPluralCount, formatters, err);
+ if (U_FAILURE(err)) {
+ uprv_free(formatters);
+ delete messageFormat;
+ }
+ }
+ if (U_SUCCESS(err)) {
+ //delete formatters[style];
+ formatters[style] = messageFormat;
+ }
+ } else {
+ delete messageFormat;
+ }
+ ures_close(countsToPatternRB);
+ ures_close(unitsRes);
+ ures_close(rb);
+ return;
+ }
+ ures_close(countsToPatternRB);
+ ures_close(unitsRes);
+ ures_close(rb);
+ status = U_ZERO_ERROR;
+ if ( locNameLen ==0 ) {
+ break;
+ }
+ }
+
+ // if no unitsShort resource was found even after fallback to root locale
+ // then search the units resource fallback from the current level to root
+ if ( locNameLen == 0 && uprv_strcmp(key, gShortUnitsTag) == 0) {
+#ifdef TMUTFMT_DEBUG
+ std::cout << "loop into searchInLocaleChain since Short-Long-Alternative \n";
+#endif
+ char pLocale[ULOC_FULLNAME_CAPACITY];
+ uprv_strcpy(pLocale, localeName);
+ // Add an underscore at the tail of locale name,
+ // so that searchInLocaleChain will check the current locale before falling back
+ uprv_strcat(pLocale, "_");
+ searchInLocaleChain(style, gUnitsTag, pLocale, srcTimeUnitField, srcPluralCount,
+ searchPluralCount, countToPatterns, err);
+ if (countToPatterns != NULL) {
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
+ if (formatters != NULL && formatters[style] != NULL) return;
+ }
+ }
+
+ // if not found the pattern for this plural count at all,
+ // fall-back to plural count "other"
+ if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) {
+ // set default fall back the same as the resource in root
+ MessageFormat* messageFormat = NULL;
+ const UChar *pattern = NULL;
+ if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
+ pattern = DEFAULT_PATTERN_FOR_SECOND;
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
+ pattern = DEFAULT_PATTERN_FOR_MINUTE;
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
+ pattern = DEFAULT_PATTERN_FOR_HOUR;
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
+ pattern = DEFAULT_PATTERN_FOR_WEEK;
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
+ pattern = DEFAULT_PATTERN_FOR_DAY;
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
+ pattern = DEFAULT_PATTERN_FOR_MONTH;
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
+ pattern = DEFAULT_PATTERN_FOR_YEAR;
+ }
+ if (pattern != NULL) {
+ messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, -1), fLocale, err);
+ }
+ if (U_SUCCESS(err)) {
+ if (fNumberFormat != NULL && messageFormat != NULL) {
+ messageFormat->setFormat(0, *fNumberFormat);
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
+ if (formatters == NULL) {
+ formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
+ formatters[UTMUTFMT_FULL_STYLE] = NULL;
+ formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
+ countToPatterns->put(srcPluralCount, formatters, err);
+ if (U_FAILURE(err)) {
+ uprv_free(formatters);
+ delete messageFormat;
+ }
+ }
+ if (U_SUCCESS(err)) {
+ //delete formatters[style];
+ formatters[style] = messageFormat;
+ }
+ } else {
+ delete messageFormat;
+ }
+ } else {
+ // fall back to rule "other", and search in parents
+ searchInLocaleChain(style, key, localeName, srcTimeUnitField, srcPluralCount,
+ gPluralCountOther, countToPatterns, err);
+ }
+}
+
+void
+TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
+ if (U_SUCCESS(status) && fLocale != locale) {
+ fLocale = locale;
+ setup(status);
+ }
+}
+
+
+void
+TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
+ if (U_FAILURE(status) || (fNumberFormat && format == *fNumberFormat)) {
+ return;
+ }
+ delete fNumberFormat;
+ fNumberFormat = (NumberFormat*)format.clone();
+ // reset the number formatter in the fTimeUnitToCountToPatterns map
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ int32_t pos = -1;
+ const UHashElement* elem = NULL;
+ while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
+ const UHashTok keyTok = elem->value;
+ MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
+ pattern[UTMUTFMT_FULL_STYLE]->setFormat(0, format);
+ pattern[UTMUTFMT_ABBREVIATED_STYLE]->setFormat(0, format);
+ }
+ }
+}
+
+
+void
+TimeUnitFormat::deleteHash(Hashtable* htable) {
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( htable ) {
+ while ( (element = htable->nextElement(pos)) != NULL ) {
+ const UHashTok valueTok = element->value;
+ const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
+ delete value[UTMUTFMT_FULL_STYLE];
+ delete value[UTMUTFMT_ABBREVIATED_STYLE];
+ //delete[] value;
+ uprv_free(value);
+ }
+ }
+ delete htable;
+}
+
+
+void
+TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
+ MessageFormat** newVal = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
+ newVal[0] = (MessageFormat*)value[0]->clone();
+ newVal[1] = (MessageFormat*)value[1]->clone();
+ target->put(UnicodeString(*key), newVal, status);
+ if ( U_FAILURE(status) ) {
+ delete newVal[0];
+ delete newVal[1];
+ uprv_free(newVal);
+ return;
+ }
+ }
+ }
+}
+
+
+U_CDECL_BEGIN
+
+/**
+ * set hash table value comparator
+ *
+ * @param val1 one value in comparison
+ * @param val2 the other value in comparison
+ * @return TRUE if 2 values are the same, FALSE otherwise
+ */
+static UBool U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2);
+
+static UBool
+U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2) {
+ const MessageFormat** pattern1 = (const MessageFormat**)val1.pointer;
+ const MessageFormat** pattern2 = (const MessageFormat**)val2.pointer;
+ return *pattern1[0] == *pattern2[0] && *pattern1[1] == *pattern2[1];
+}
+
+U_CDECL_END
+
+Hashtable*
+TimeUnitFormat::initHash(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if ( U_FAILURE(status) ) {
+ delete hTable;
+ return NULL;
+ }
+ hTable->setValueComparator(tmutfmtHashTableValueComparator);
+ return hTable;
+}
+
+
+const char*
+TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ switch (unitField) {
+ case TimeUnit::UTIMEUNIT_YEAR:
+ return gTimeUnitYear;
+ case TimeUnit::UTIMEUNIT_MONTH:
+ return gTimeUnitMonth;
+ case TimeUnit::UTIMEUNIT_DAY:
+ return gTimeUnitDay;
+ case TimeUnit::UTIMEUNIT_WEEK:
+ return gTimeUnitWeek;
+ case TimeUnit::UTIMEUNIT_HOUR:
+ return gTimeUnitHour;
+ case TimeUnit::UTIMEUNIT_MINUTE:
+ return gTimeUnitMinute;
+ case TimeUnit::UTIMEUNIT_SECOND:
+ return gTimeUnitSecond;
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tolowtrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tolowtrn.cpp
new file mode 100644
index 00000000000..c93f4d0eff8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/tolowtrn.h b/Build/source/libs/icu/icu-4.8.1/i18n/tolowtrn.h
new file mode 100644
index 00000000000..564b215a728
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/toupptrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/toupptrn.cpp
new file mode 100644
index 00000000000..4b7c7d06aca
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/toupptrn.h b/Build/source/libs/icu/icu-4.8.1/i18n/toupptrn.h
new file mode 100644
index 00000000000..77799acbfd6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/translit.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/translit.cpp
new file mode 100644
index 00000000000..84364796af9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/translit.cpp
@@ -0,0 +1,1644 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2010, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/17/99 aliu Creation.
+ **********************************************************************
+ */
+
+#include <typeinfo> // for 'typeid' to work
+
+#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 "brktrans.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(status) (registry!=0 || initializeRegistry(status))
+
+// 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);
+ }
+ // Check null pointer
+ if (t != NULL) {
+ t->setID(canonID);
+ if (globalFilter != NULL) {
+ t->adoptFilter(globalFilter);
+ }
+ }
+ else if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ 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_lock(&registryMutex);
+ if (HAVE_REGISTRY(ec)) {
+ 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(ec)) {
+ 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 && typeid(*temp) != typeid(NullTransliterator))
+ transliterators.addElement(temp, status);
+ else
+ delete temp;
+ }
+ }
+ if (!parser.dataVector.isEmpty()) {
+ TransliterationRuleData* data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
+ RuleBasedTransliterator* temprbt = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + (passNumber++),
+ data, TRUE);
+ // Check if NULL before adding it to transliterators to avoid future usage of NULL pointer.
+ if (temprbt == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return t;
+ }
+ transliterators.addElement(temprbt, status);
+ }
+ }
+
+ t = new CompoundTransliterator(transliterators, passNumber - 1, parseError, status);
+ // Null pointer check
+ if (t != NULL) {
+ t->setID(ID);
+ t->adoptFilter(parser.orphanCompoundFilter());
+ }
+ }
+ if (U_SUCCESS(status) && t == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ 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 {
+ const CompoundTransliterator* ct = dynamic_cast<const CompoundTransliterator*>(this);
+ return ct != NULL ? ct->getCount() : 0;
+}
+
+const Transliterator& Transliterator::getElement(int32_t index, UErrorCode& ec) const {
+ if (U_FAILURE(ec)) {
+ return *this;
+ }
+ const CompoundTransliterator* cpd = dynamic_cast<const CompoundTransliterator*>(this);
+ 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 = dynamic_cast<UnicodeSet*>(filter);
+ UBool deleteFilterSet = FALSE;
+ // Most, but not all filters will be UnicodeSets. Optimize for
+ // the high-runner case.
+ if (filterSet == NULL) {
+ filterSet = new UnicodeSet();
+ // Check null pointer
+ if (filterSet == NULL) {
+ return result;
+ }
+ 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) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ _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) {
+ UErrorCode ec = U_ZERO_ERROR;
+ registry->put(id, factory, context, TRUE, ec);
+}
+
+// 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) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ _registerInstance(adoptedPrototype);
+ }
+}
+
+void Transliterator::_registerInstance(Transliterator* adoptedPrototype) {
+ UErrorCode ec = U_ZERO_ERROR;
+ registry->put(adoptedPrototype, TRUE, ec);
+}
+
+void U_EXPORT2 Transliterator::registerAlias(const UnicodeString& aliasID,
+ const UnicodeString& realID) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ _registerAlias(aliasID, realID);
+ }
+}
+
+void Transliterator::_registerAlias(const UnicodeString& aliasID,
+ const UnicodeString& realID) {
+ UErrorCode ec = U_ZERO_ERROR;
+ registry->put(aliasID, realID, FALSE, TRUE, ec);
+}
+
+/**
+ * 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) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ 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) {
+ int32_t retVal = 0;
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ retVal = registry->countAvailableIDs();
+ }
+ return retVal;
+}
+
+/**
+ * == 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_lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ 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_lock(&registryMutex);
+ if (HAVE_REGISTRY(ec)) {
+ result = registry->getAvailableIDs();
+ }
+ umtx_unlock(&registryMutex);
+ if (result == NULL) {
+ ec = U_INTERNAL_TRANSLITERATOR_ERROR;
+ }
+ return result;
+}
+
+int32_t U_EXPORT2 Transliterator::countAvailableSources(void) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ return HAVE_REGISTRY(ec) ? _countAvailableSources() : 0;
+}
+
+UnicodeString& U_EXPORT2 Transliterator::getAvailableSource(int32_t index,
+ UnicodeString& result) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ _getAvailableSource(index, result);
+ }
+ return result;
+}
+
+int32_t U_EXPORT2 Transliterator::countAvailableTargets(const UnicodeString& source) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ return HAVE_REGISTRY(ec) ? _countAvailableTargets(source) : 0;
+}
+
+UnicodeString& U_EXPORT2 Transliterator::getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ _getAvailableTarget(index, source, result);
+ }
+ return result;
+}
+
+int32_t U_EXPORT2 Transliterator::countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ return HAVE_REGISTRY(ec) ? _countAvailableVariants(source, target) : 0;
+}
+
+UnicodeString& U_EXPORT2 Transliterator::getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result) {
+ Mutex lock(&registryMutex);
+ UErrorCode ec = U_ZERO_ERROR;
+ if (HAVE_REGISTRY(ec)) {
+ _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 entire
+ * 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(UErrorCode &status) {
+ if (registry != 0) {
+ return TRUE;
+ }
+
+ 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, status);
+ }
+ break;
+ case 0x61: // 'a'
+ // 'alias'; row[2]=createInstance argument
+ resString = ures_getString(res, &len, &status);
+ registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE, status);
+ 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.
+
+ // This is to allow for null pointer check
+ NullTransliterator* tempNullTranslit = new NullTransliterator();
+ LowercaseTransliterator* tempLowercaseTranslit = new LowercaseTransliterator();
+ UppercaseTransliterator* tempUppercaseTranslit = new UppercaseTransliterator();
+ TitlecaseTransliterator* tempTitlecaseTranslit = new TitlecaseTransliterator();
+ UnicodeNameTransliterator* tempUnicodeTranslit = new UnicodeNameTransliterator();
+ NameUnicodeTransliterator* tempNameUnicodeTranslit = new NameUnicodeTransliterator();
+#if !UCONFIG_NO_BREAK_ITERATION
+ // TODO: could or should these transliterators be referenced polymorphically once constructed?
+ BreakTransliterator* tempBreakTranslit = new BreakTransliterator();
+#endif
+ // Check for null pointers
+ if (tempNullTranslit == NULL || tempLowercaseTranslit == NULL || tempUppercaseTranslit == NULL ||
+ tempTitlecaseTranslit == NULL || tempUnicodeTranslit == NULL ||
+#if !UCONFIG_NO_BREAK_ITERATION
+ tempBreakTranslit == NULL ||
+#endif
+ tempNameUnicodeTranslit == NULL )
+ {
+ delete tempNullTranslit;
+ delete tempLowercaseTranslit;
+ delete tempUppercaseTranslit;
+ delete tempTitlecaseTranslit;
+ delete tempUnicodeTranslit;
+ delete tempNameUnicodeTranslit;
+#if !UCONFIG_NO_BREAK_ITERATION
+ delete tempBreakTranslit;
+#endif
+ // Since there was an error, remove registry
+ delete registry;
+ registry = NULL;
+
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ registry->put(tempNullTranslit, TRUE, status);
+ registry->put(tempLowercaseTranslit, TRUE, status);
+ registry->put(tempUppercaseTranslit, TRUE, status);
+ registry->put(tempTitlecaseTranslit, TRUE, status);
+ registry->put(tempUnicodeTranslit, TRUE, status);
+ registry->put(tempNameUnicodeTranslit, TRUE, status);
+#if !UCONFIG_NO_BREAK_ITERATION
+ registry->put(tempBreakTranslit, FALSE, status); // FALSE means invisible.
+#endif
+
+ 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, utrans_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 utrans_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-4.8.1/i18n/transreg.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/transreg.cpp
new file mode 100644
index 00000000000..8e1d4f431fd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/transreg.cpp
@@ -0,0 +1,1359 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2010, 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 TransliteratorSpec
+//----------------------------------------------------------------------
+
+/**
+ * A TransliteratorSpec 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 TransliteratorSpec : public UMemory {
+ public:
+ TransliteratorSpec(const UnicodeString& spec);
+ ~TransliteratorSpec();
+
+ 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;
+
+ TransliteratorSpec(const TransliteratorSpec &other); // forbid copying of this class
+ TransliteratorSpec &operator=(const TransliteratorSpec &other); // forbid copying of this class
+};
+
+TransliteratorSpec::TransliteratorSpec(const UnicodeString& theSpec)
+: top(theSpec),
+ res(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ 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(CharString().appendInvariantChars(theSpec, status).data(),
+ 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();
+}
+
+TransliteratorSpec::~TransliteratorSpec() {
+ delete res;
+}
+
+UBool TransliteratorSpec::hasFallback() const {
+ return nextSpec.length() != 0;
+}
+
+void TransliteratorSpec::reset() {
+ if (spec != top) {
+ spec = top;
+ isSpecLocale = (res != 0);
+ setupNext();
+ }
+}
+
+void TransliteratorSpec::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& TransliteratorSpec::next() {
+ spec = nextSpec;
+ isSpecLocale = isNextLocale;
+ setupNext();
+ return spec;
+}
+
+const UnicodeString& TransliteratorSpec::get() const {
+ return spec;
+}
+
+UBool TransliteratorSpec::isLocale() const {
+ return isSpecLocale;
+}
+
+ResourceBundle& TransliteratorSpec::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(TransliteratorEntry* e) {
+ for (int i=0; i<DEBUG_entries->size(); ++i) {
+ if (e == (TransliteratorEntry*) DEBUG_entries->elementAt(i)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Track object creation
+static void DEBUG_newEntry(TransliteratorEntry* 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(TransliteratorEntry* 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(TransliteratorEntry* 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 TransliteratorEntry : 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;
+ TransliteratorEntry();
+ ~TransliteratorEntry();
+ void adoptPrototype(Transliterator* adopted);
+ void setFactory(Transliterator::Factory factory,
+ Transliterator::Token context);
+
+private:
+
+ TransliteratorEntry(const TransliteratorEntry &other); // forbid copying of this class
+ TransliteratorEntry &operator=(const TransliteratorEntry &other); // forbid copying of this class
+};
+
+TransliteratorEntry::TransliteratorEntry() {
+ u.prototype = 0;
+ compoundFilter = NULL;
+ entryType = NONE;
+ DEBUG_newEntry(this);
+}
+
+TransliteratorEntry::~TransliteratorEntry() {
+ 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 TransliteratorEntry::adoptPrototype(Transliterator* adopted) {
+ if (entryType == PROTOTYPE) {
+ delete u.prototype;
+ }
+ entryType = PROTOTYPE;
+ u.prototype = adopted;
+}
+
+void TransliteratorEntry::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 (TransliteratorEntry*) 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);
+ TransliteratorEntry *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);
+ TransliteratorEntry *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 == TransliteratorEntry::RULES_FORWARD ||
+ entry->entryType == TransliteratorEntry::RULES_REVERSE ||
+ entry->entryType == TransliteratorEntry::LOCALE_RULES) {
+
+ if (parser.idBlockVector.isEmpty() && parser.dataVector.isEmpty()) {
+ entry->u.data = 0;
+ entry->entryType = TransliteratorEntry::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 = TransliteratorEntry::RBT_DATA;
+ }
+ else if (parser.idBlockVector.size() == 1 && parser.dataVector.isEmpty()) {
+ entry->stringArg = *(UnicodeString*)(parser.idBlockVector.elementAt(0));
+ entry->compoundFilter = parser.orphanCompoundFilter();
+ entry->entryType = TransliteratorEntry::ALIAS;
+ }
+ else {
+ entry->entryType = TransliteratorEntry::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,
+ UErrorCode& ec)
+{
+ TransliteratorEntry *entry = new TransliteratorEntry();
+ if (entry == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ entry->adoptPrototype(adoptedProto);
+ registerEntry(adoptedProto->getID(), entry, visible);
+}
+
+void TransliteratorRegistry::put(const UnicodeString& ID,
+ Transliterator::Factory factory,
+ Transliterator::Token context,
+ UBool visible,
+ UErrorCode& ec) {
+ TransliteratorEntry *entry = new TransliteratorEntry();
+ if (entry == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ entry->setFactory(factory, context);
+ registerEntry(ID, entry, visible);
+}
+
+void TransliteratorRegistry::put(const UnicodeString& ID,
+ const UnicodeString& resourceName,
+ UTransDirection dir,
+ UBool readonlyResourceAlias,
+ UBool visible,
+ UErrorCode& ec) {
+ TransliteratorEntry *entry = new TransliteratorEntry();
+ if (entry == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ entry->entryType = (dir == UTRANS_FORWARD) ? TransliteratorEntry::RULES_FORWARD
+ : TransliteratorEntry::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,
+ UErrorCode& /*ec*/) {
+ TransliteratorEntry *entry = new TransliteratorEntry();
+ // Null pointer check
+ if (entry != NULL) {
+ entry->entryType = TransliteratorEntry::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,
+ TransliteratorEntry* 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,
+ TransliteratorEntry* 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,
+ TransliteratorEntry* 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();
+ // Check to make sure newID was created.
+ if (newID != NULL) {
+ // 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_deleteUObject);
+ 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)) {
+ UnicodeString *tempus; // Used for null pointer check.
+ if (variant.length() > 0) {
+ tempus = new UnicodeString(variant);
+ if (tempus != NULL) {
+ variants->addElement(tempus, status);
+ }
+ } else {
+ tempus = new UnicodeString(NO_VARIANT) ;
+ if (tempus != NULL) {
+ variants->insertElementAt(tempus, 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.
+ */
+TransliteratorEntry* TransliteratorRegistry::findInDynamicStore(const TransliteratorSpec& src,
+ const TransliteratorSpec& trg,
+ const UnicodeString& variant) const {
+ UnicodeString ID;
+ TransliteratorIDParser::STVtoID(src, trg, variant, ID);
+ TransliteratorEntry *e = (TransliteratorEntry*) 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.
+ */
+TransliteratorEntry* TransliteratorRegistry::findInStaticStore(const TransliteratorSpec& src,
+ const TransliteratorSpec& trg,
+ const UnicodeString& variant) {
+ TransliteratorEntry* 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.
+ */
+TransliteratorEntry* TransliteratorRegistry::findInBundle(const TransliteratorSpec& specToOpen,
+ const TransliteratorSpec& 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(""));
+ UErrorCode status = U_ZERO_ERROR;
+ ResourceBundle subres(specToOpen.getBundle().get(
+ CharString().appendInvariantChars(utag, status).data(), 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) {
+ status = U_ZERO_ERROR;
+ resStr = subres.getStringEx(
+ CharString().appendInvariantChars(variant, status).data(), 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.
+ TransliteratorEntry *entry = new TransliteratorEntry();
+ 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 = TransliteratorEntry::LOCALE_RULES;
+ entry->stringArg = resStr;
+ entry->intArg = dir;
+ }
+
+ return entry;
+}
+
+/**
+ * Convenience method. Calls 3-arg find().
+ */
+TransliteratorEntry* 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.
+ */
+TransliteratorEntry* TransliteratorRegistry::find(UnicodeString& source,
+ UnicodeString& target,
+ UnicodeString& variant) {
+
+ TransliteratorSpec src(source);
+ TransliteratorSpec trg(target);
+ TransliteratorEntry* entry;
+
+ // Seek exact match in hashtable. Temporary fix for ICU 4.6.
+ // TODO: The general logic for finding a matching transliterator needs to be reviewed.
+ // ICU ticket #8089
+ UnicodeString ID;
+ TransliteratorIDParser::STVtoID(source, target, variant, ID);
+ entry = (TransliteratorEntry*) registry.get(ID);
+ if (entry != 0) {
+ // std::string ss;
+ // std::cout << ID.toUTF8String(ss) << std::endl;
+ return 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,
+ TransliteratorEntry *entry,
+ TransliteratorAlias* &aliasReturn,
+ UErrorCode& status) {
+ Transliterator *t = 0;
+ U_ASSERT(aliasReturn == 0);
+
+ switch (entry->entryType) {
+ case TransliteratorEntry::RBT_DATA:
+ t = new RuleBasedTransliterator(ID, entry->u.data);
+ if (t == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
+ case TransliteratorEntry::PROTOTYPE:
+ t = entry->u.prototype->clone();
+ if (t == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
+ case TransliteratorEntry::ALIAS:
+ aliasReturn = new TransliteratorAlias(entry->stringArg, entry->compoundFilter);
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ case TransliteratorEntry::FACTORY:
+ t = entry->u.factory.function(ID, entry->u.factory.context);
+ if (t == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
+ case TransliteratorEntry::COMPOUND_RBT:
+ {
+ UVector* rbts = new UVector(entry->u.dataVector->size(), status);
+ // Check for null pointer
+ if (rbts == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ 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)) {
+ delete rbts;
+ return 0;
+ }
+ aliasReturn = new TransliteratorAlias(ID, entry->stringArg, rbts, entry->compoundFilter);
+ }
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ case TransliteratorEntry::LOCALE_RULES:
+ aliasReturn = new TransliteratorAlias(ID, entry->stringArg,
+ (UTransDirection) entry->intArg);
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ case TransliteratorEntry::RULES_FORWARD:
+ case TransliteratorEntry::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 == TransliteratorEntry::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-4.8.1/i18n/transreg.h b/Build/source/libs/icu/icu-4.8.1/i18n/transreg.h
new file mode 100644
index 00000000000..483e74f4560
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/transreg.h
@@ -0,0 +1,462 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2008, 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 TransliteratorEntry;
+class TransliteratorSpec;
+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,
+ UErrorCode& ec);
+
+ /**
+ * 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,
+ UErrorCode& ec);
+
+ /**
+ * 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,
+ UErrorCode& ec);
+
+ /**
+ * 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,
+ UErrorCode& ec);
+
+ /**
+ * 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
+ //----------------------------------------------------------------
+
+ TransliteratorEntry* find(const UnicodeString& ID);
+
+ TransliteratorEntry* find(UnicodeString& source,
+ UnicodeString& target,
+ UnicodeString& variant);
+
+ TransliteratorEntry* findInDynamicStore(const TransliteratorSpec& src,
+ const TransliteratorSpec& trg,
+ const UnicodeString& variant) const;
+
+ TransliteratorEntry* findInStaticStore(const TransliteratorSpec& src,
+ const TransliteratorSpec& trg,
+ const UnicodeString& variant);
+
+ static TransliteratorEntry* findInBundle(const TransliteratorSpec& specToOpen,
+ const TransliteratorSpec& specToFind,
+ const UnicodeString& variant,
+ UTransDirection direction);
+
+ void registerEntry(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ TransliteratorEntry* adopted,
+ UBool visible);
+
+ void registerEntry(const UnicodeString& ID,
+ TransliteratorEntry* adopted,
+ UBool visible);
+
+ void registerEntry(const UnicodeString& ID,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ TransliteratorEntry* 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,
+ TransliteratorEntry *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-4.8.1/i18n/tridpars.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tridpars.cpp
new file mode 100644
index 00000000000..cf9fd3fb5b6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tridpars.cpp
@@ -0,0 +1,938 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2009, 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);
+ // Null pointers check
+ if (b == NULL || single == NULL) {
+ delete b;
+ delete single;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ 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);
+ // Check for null pointer.
+ if (a == NULL || single == NULL) {
+ delete a;
+ delete single;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ 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);
+ }
+ }
+ // Check for NULL pointer
+ if (single == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ 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);
+ if (single != NULL) {
+ 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;
+ }
+
+ Mutex lock(&LOCK);
+
+ UnicodeString *tempus = new UnicodeString(inverseTarget); // Used for null pointer check before usage.
+ if (tempus == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ SPECIAL_INVERSES->put(target, tempus, status);
+ if (bidirectional) {
+ tempus = new UnicodeString(target);
+ if (tempus == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ SPECIAL_INVERSES->put(inverseTarget, tempus, 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_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);
+ // Null pointer check
+ if (special_inverses == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ special_inverses->setValueDeleter(uhash_deleteUnicodeString);
+
+ 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, utrans_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-4.8.1/i18n/tridpars.h b/Build/source/libs/icu/icu-4.8.1/i18n/tridpars.h
new file mode 100644
index 00000000000..1f2268fb111
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tridpars.h
@@ -0,0 +1,361 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2002-2010, 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 required. 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-4.8.1/i18n/tzfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.cpp
new file mode 100644
index 00000000000..128d156ffe4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.cpp
@@ -0,0 +1,534 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tzfmt.h"
+#include "tzgnames.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uhash.h"
+#include "umutex.h"
+#include "zonemeta.h"
+
+U_NAMESPACE_BEGIN
+
+// ---------------------------------------------------
+// TimeZoneFormatImpl - the TimeZoneFormat implementation
+// ---------------------------------------------------
+class TimeZoneFormatImpl : public TimeZoneFormat {
+public:
+ TimeZoneFormatImpl(const Locale& locale, UErrorCode& status);
+ virtual ~TimeZoneFormatImpl();
+
+ const TimeZoneNames* getTimeZoneNames() const;
+
+ UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
+ UnicodeString& name, UTimeZoneTimeType* timeType = NULL) const;
+
+ UnicodeString& parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UnicodeString& tzID, UTimeZoneTimeType* timeType = NULL) const;
+
+private:
+ UMTX fLock;
+ Locale fLocale;
+ char fTargetRegion[ULOC_COUNTRY_CAPACITY];
+ TimeZoneNames* fTimeZoneNames;
+ TimeZoneGenericNames* fTimeZoneGenericNames;
+
+ UnicodeString& formatGeneric(const TimeZone& tz, UTimeZoneGenericNameType genType, UDate date, UnicodeString& name) const;
+
+ UnicodeString& formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UTimeZoneNameType dstType,
+ UDate date, UnicodeString& name, UTimeZoneTimeType *timeType) const;
+
+ const TimeZoneGenericNames* getTimeZoneGenericNames(UErrorCode& status) const;
+};
+
+TimeZoneFormatImpl::TimeZoneFormatImpl(const Locale& locale, UErrorCode& status)
+: fLock(NULL),fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL) {
+
+ const char* region = fLocale.getCountry();
+ int32_t regionLen = uprv_strlen(region);
+ if (regionLen == 0) {
+ char loc[ULOC_FULLNAME_CAPACITY];
+ uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
+
+ regionLen = uloc_getCountry(loc, fTargetRegion, sizeof(fTargetRegion), &status);
+ if (U_SUCCESS(status)) {
+ fTargetRegion[regionLen] = 0;
+ } else {
+ return;
+ }
+ } else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
+ uprv_strcpy(fTargetRegion, region);
+ } else {
+ fTargetRegion[0] = 0;
+ }
+
+ fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
+ // fTimeZoneGenericNames is lazily instantiated
+}
+
+TimeZoneFormatImpl::~TimeZoneFormatImpl() {
+ if (fTimeZoneNames != NULL) {
+ delete fTimeZoneNames;
+ }
+ if (fTimeZoneGenericNames != NULL) {
+ delete fTimeZoneGenericNames;
+ }
+ umtx_destroy(&fLock);
+}
+
+const TimeZoneNames*
+TimeZoneFormatImpl::getTimeZoneNames() const {
+ return fTimeZoneNames;
+}
+
+const TimeZoneGenericNames*
+TimeZoneFormatImpl::getTimeZoneGenericNames(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UBool create;
+ UMTX_CHECK(&gZoneMetaLock, (fTimeZoneGenericNames == NULL), create);
+ if (create) {
+ TimeZoneFormatImpl *nonConstThis = const_cast<TimeZoneFormatImpl *>(this);
+ umtx_lock(&nonConstThis->fLock);
+ {
+ if (fTimeZoneGenericNames == NULL) {
+ nonConstThis->fTimeZoneGenericNames = new TimeZoneGenericNames(fLocale, status);
+ if (U_SUCCESS(status) && fTimeZoneGenericNames == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ }
+ umtx_unlock(&nonConstThis->fLock);
+ }
+
+ return fTimeZoneGenericNames;
+}
+
+UnicodeString&
+TimeZoneFormatImpl::format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
+ UnicodeString& name, UTimeZoneTimeType* timeType /* = NULL */) const {
+ if (timeType) {
+ *timeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ }
+ switch (style) {
+ case UTZFMT_STYLE_LOCATION:
+ formatGeneric(tz, UTZGNM_LOCATION, date, name);
+ break;
+ case UTZFMT_STYLE_GENERIC_LONG:
+ formatGeneric(tz, UTZGNM_LONG, date, name);
+ break;
+ case UTZFMT_STYLE_GENERIC_SHORT:
+ formatGeneric(tz, UTZGNM_SHORT, date, name);
+ break;
+ case UTZFMT_STYLE_SPECIFIC_LONG:
+ formatSpecific(tz, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT, date, name, timeType);
+ break;
+ case UTZFMT_STYLE_SPECIFIC_SHORT:
+ formatSpecific(tz, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT, date, name, timeType);
+ break;
+ case UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED:
+ formatSpecific(tz, UTZNM_SHORT_STANDARD_COMMONLY_USED, UTZNM_SHORT_DAYLIGHT_COMMONLY_USED, date, name, timeType);
+ break;
+ }
+ return name;
+}
+
+UnicodeString&
+TimeZoneFormatImpl::parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UnicodeString& tzID, UTimeZoneTimeType* timeType /* = NULL */) const {
+ if (timeType) {
+ *timeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ }
+ tzID.setToBogus();
+
+ int32_t startIdx = pos.getIndex();
+
+ UBool isGeneric = FALSE;
+ uint32_t types = 0;
+
+ switch (style) {
+ case UTZFMT_STYLE_LOCATION:
+ isGeneric = TRUE;
+ types = UTZGNM_LOCATION;
+ break;
+ case UTZFMT_STYLE_GENERIC_LONG:
+ isGeneric = TRUE;
+ types = UTZGNM_LOCATION | UTZGNM_LONG;
+ break;
+ case UTZFMT_STYLE_GENERIC_SHORT:
+ isGeneric = TRUE;
+ types = UTZGNM_LOCATION | UTZGNM_SHORT;
+ break;
+ case UTZFMT_STYLE_SPECIFIC_LONG:
+ types = UTZNM_LONG_STANDARD | UTZNM_LONG_DAYLIGHT;
+ break;
+ case UTZFMT_STYLE_SPECIFIC_SHORT:
+ types = UTZNM_SHORT_STANDARD | UTZNM_SHORT_DAYLIGHT;
+ break;
+ case UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED:
+ types = UTZNM_SHORT_STANDARD_COMMONLY_USED | UTZNM_SHORT_DAYLIGHT_COMMONLY_USED;
+ break;
+ }
+
+ UTimeZoneTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ UnicodeString parsedTzID;
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (isGeneric) {
+ int32_t len = 0;
+ const TimeZoneGenericNames *gnames = getTimeZoneGenericNames(status);
+ if (U_SUCCESS(status)) {
+ len = gnames->findBestMatch(text, startIdx, types, parsedTzID, parsedTimeType, status);
+ }
+ if (U_FAILURE(status) || len == 0) {
+ pos.setErrorIndex(startIdx);
+ return tzID;
+ }
+ pos.setIndex(startIdx + len);
+ } else {
+ TimeZoneNameMatchInfo *matchInfo = fTimeZoneNames->find(text, startIdx, types, status);
+ if (U_FAILURE(status) || matchInfo == NULL) {
+ pos.setErrorIndex(startIdx);
+ return tzID;
+ }
+ int32_t bestLen = 0;
+ int32_t bestIdx = -1;
+ for (int32_t i = 0; i < matchInfo->size(); i++) {
+ int32_t matchLen = matchInfo->getMatchLength(i);
+ if (matchLen > bestLen) {
+ bestLen = matchLen;
+ bestIdx = i;
+ }
+ }
+ if (bestIdx >= 0) {
+ matchInfo->getTimeZoneID(bestIdx, parsedTzID);
+ if (parsedTzID.isEmpty()) {
+ UnicodeString mzID;
+ matchInfo->getMetaZoneID(bestIdx, mzID);
+ U_ASSERT(mzID.length() > 0);
+ fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, parsedTzID);
+ }
+ UTimeZoneNameType nameType = matchInfo->getNameType(bestIdx);
+ switch (nameType) {
+ case UTZNM_LONG_STANDARD:
+ case UTZNM_SHORT_STANDARD:
+ case UTZNM_SHORT_STANDARD_COMMONLY_USED:
+ parsedTimeType = UTZFMT_TIME_TYPE_STANDARD;
+ break;
+ case UTZNM_LONG_DAYLIGHT:
+ case UTZNM_SHORT_DAYLIGHT:
+ case UTZNM_SHORT_DAYLIGHT_COMMONLY_USED:
+ parsedTimeType = UTZFMT_TIME_TYPE_DAYLIGHT;
+ break;
+ default:
+ parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ break;
+ }
+ pos.setIndex(startIdx + bestLen);
+ }
+ delete matchInfo;
+ }
+ if (timeType) {
+ *timeType = parsedTimeType;
+ }
+ tzID.setTo(parsedTzID);
+ return tzID;
+}
+
+UnicodeString&
+TimeZoneFormatImpl::formatGeneric(const TimeZone& tz, UTimeZoneGenericNameType genType, UDate date, UnicodeString& name) const {
+ UErrorCode status = U_ZERO_ERROR;
+ const TimeZoneGenericNames* gnames = getTimeZoneGenericNames(status);
+ if (U_FAILURE(status)) {
+ name.setToBogus();
+ return name;
+ }
+
+ if (genType == UTZGNM_LOCATION) {
+ const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(tz);
+ if (canonicalID == NULL) {
+ name.setToBogus();
+ return name;
+ }
+ return gnames->getGenericLocationName(UnicodeString(canonicalID), name);
+ }
+ return gnames->getDisplayName(tz, genType, date, name);
+}
+
+UnicodeString&
+TimeZoneFormatImpl::formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UTimeZoneNameType dstType,
+ UDate date, UnicodeString& name, UTimeZoneTimeType *timeType) const {
+ if (fTimeZoneNames == NULL) {
+ name.setToBogus();
+ return name;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UBool isDaylight = tz.inDaylightTime(date, status);
+ const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(tz);
+
+ if (U_FAILURE(status) || canonicalID == NULL) {
+ name.setToBogus();
+ return name;
+ }
+
+ if (isDaylight) {
+ fTimeZoneNames->getDisplayName(UnicodeString(canonicalID), dstType, date, name);
+ } else {
+ fTimeZoneNames->getDisplayName(UnicodeString(canonicalID), stdType, date, name);
+ }
+
+ if (timeType && !name.isEmpty()) {
+ *timeType = isDaylight ? UTZFMT_TIME_TYPE_DAYLIGHT : UTZFMT_TIME_TYPE_STANDARD;
+ }
+ return name;
+}
+
+
+// TimeZoneFormat object cache handling
+static UMTX gTimeZoneFormatLock = NULL;
+static UHashtable *gTimeZoneFormatCache = NULL;
+static UBool gTimeZoneFormatCacheInitialized = FALSE;
+
+// Access count - incremented every time up to SWEEP_INTERVAL,
+// then reset to 0
+static int32_t gAccessCount = 0;
+
+// Interval for calling the cache sweep function - every 100 times
+#define SWEEP_INTERVAL 100
+
+// Cache expiration in millisecond. When a cached entry is no
+// longer referenced and exceeding this threshold since last
+// access time, then the cache entry will be deleted by the sweep
+// function. For now, 3 minutes.
+#define CACHE_EXPIRATION 180000.0
+
+typedef struct TimeZoneFormatCacheEntry {
+ TimeZoneFormat* tzfmt;
+ int32_t refCount;
+ double lastAccess;
+} TimeZoneNameFormatCacheEntry;
+
+U_CDECL_BEGIN
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV timeZoneFormat_cleanup(void)
+{
+ umtx_destroy(&gTimeZoneFormatLock);
+
+ if (gTimeZoneFormatCache != NULL) {
+ uhash_close(gTimeZoneFormatCache);
+ gTimeZoneFormatCache = NULL;
+ }
+ gTimeZoneFormatCacheInitialized = FALSE;
+ return TRUE;
+}
+
+/**
+ * Deleter for TimeZoneNamesCacheEntry
+ */
+static void U_CALLCONV
+deleteTimeZoneFormatCacheEntry(void *obj) {
+ TimeZoneNameFormatCacheEntry *entry = (TimeZoneNameFormatCacheEntry *)obj;
+ delete (TimeZoneFormat *) entry->tzfmt;
+ uprv_free((void *)entry);
+}
+U_CDECL_END
+
+/**
+ * Function used for removing unreferrenced cache entries exceeding
+ * the expiration time. This function must be called with in the mutex
+ * block.
+ */
+static void sweepCache() {
+ int32_t pos = -1;
+ const UHashElement* elem;
+ double now = (double)uprv_getUTCtime();
+
+ while ((elem = uhash_nextElement(gTimeZoneFormatCache, &pos))) {
+ TimeZoneFormatCacheEntry *entry = (TimeZoneFormatCacheEntry *)elem->value.pointer;
+ if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
+ // delete this entry
+ uhash_removeElement(gTimeZoneFormatCache, elem);
+ }
+ }
+}
+
+// ---------------------------------------------------
+// TimeZoneFormatDelegate
+// This class wraps a TimeZoneFormatImpl singleton
+// per locale and maintain the reference count.
+// ---------------------------------------------------
+class TimeZoneFormatDelegate : public TimeZoneFormat {
+public:
+ TimeZoneFormatDelegate(const Locale& locale, UErrorCode& status);
+ virtual ~TimeZoneFormatDelegate();
+
+ const TimeZoneNames* getTimeZoneNames() const;
+
+ UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
+ UnicodeString& name, UTimeZoneTimeType* timeType = NULL) const;
+
+ UnicodeString& parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UnicodeString& tzID, UTimeZoneTimeType* timeType = NULL) const;
+
+private:
+ TimeZoneFormatCacheEntry* fTZfmtCacheEntry;
+};
+
+TimeZoneFormatDelegate::TimeZoneFormatDelegate(const Locale& locale, UErrorCode& status) {
+ UBool initialized;
+ UMTX_CHECK(&gTimeZoneFormatLock, gTimeZoneFormatCacheInitialized, initialized);
+ if (!initialized) {
+ // Create empty hashtable
+ umtx_lock(&gTimeZoneFormatLock);
+ {
+ if (!gTimeZoneFormatCacheInitialized) {
+ gTimeZoneFormatCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+ if (U_SUCCESS(status)) {
+ uhash_setKeyDeleter(gTimeZoneFormatCache, uhash_freeBlock);
+ uhash_setValueDeleter(gTimeZoneFormatCache, deleteTimeZoneFormatCacheEntry);
+ gTimeZoneFormatCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, timeZoneFormat_cleanup);
+ }
+ }
+ }
+ umtx_unlock(&gTimeZoneFormatLock);
+ }
+
+ // Check the cache, if not available, create new one and cache
+ TimeZoneFormatCacheEntry *cacheEntry = NULL;
+ umtx_lock(&gTimeZoneFormatLock);
+ {
+ const char *key = locale.getName();
+ cacheEntry = (TimeZoneFormatCacheEntry *)uhash_get(gTimeZoneFormatCache, key);
+ if (cacheEntry == NULL) {
+ TimeZoneFormat *tzfmt = NULL;
+ char *newKey = NULL;
+
+ tzfmt = new TimeZoneFormatImpl(locale, status);
+ if (tzfmt == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_SUCCESS(status)) {
+ newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
+ if (newKey == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ uprv_strcpy(newKey, key);
+ }
+ }
+ if (U_SUCCESS(status)) {
+ cacheEntry = (TimeZoneFormatCacheEntry *)uprv_malloc(sizeof(TimeZoneFormatCacheEntry));
+ if (cacheEntry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ cacheEntry->tzfmt = tzfmt;
+ cacheEntry->refCount = 1;
+ cacheEntry->lastAccess = (double)uprv_getUTCtime();
+
+ uhash_put(gTimeZoneFormatCache, newKey, cacheEntry, &status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ if (tzfmt != NULL) {
+ delete tzfmt;
+ }
+ if (newKey != NULL) {
+ uprv_free(newKey);
+ }
+ if (cacheEntry != NULL) {
+ uprv_free(cacheEntry);
+ }
+ return;
+ }
+ } else {
+ // Update the reference count
+ cacheEntry->refCount++;
+ cacheEntry->lastAccess = (double)uprv_getUTCtime();
+ }
+ gAccessCount++;
+ if (gAccessCount >= SWEEP_INTERVAL) {
+ // sweep
+ sweepCache();
+ gAccessCount = 0;
+ }
+ }
+ umtx_unlock(&gTimeZoneFormatLock);
+
+ fTZfmtCacheEntry = cacheEntry;
+}
+
+TimeZoneFormatDelegate::~TimeZoneFormatDelegate() {
+ umtx_lock(&gTimeZoneFormatLock);
+ {
+ U_ASSERT(fTZfmtCacheEntry->refCount > 0);
+ // Just decrement the reference count
+ fTZfmtCacheEntry->refCount--;
+ }
+ umtx_unlock(&gTimeZoneFormatLock);
+}
+
+const TimeZoneNames*
+TimeZoneFormatDelegate::getTimeZoneNames() const {
+ return fTZfmtCacheEntry->tzfmt->getTimeZoneNames();
+}
+
+UnicodeString&
+TimeZoneFormatDelegate::format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
+ UnicodeString& name, UTimeZoneTimeType* timeType /* = NULL */) const {
+ return fTZfmtCacheEntry->tzfmt->format(style, tz, date, name, timeType);
+}
+
+UnicodeString&
+TimeZoneFormatDelegate::parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UnicodeString& tzID, UTimeZoneTimeType* timeType /* = NULL */) const {
+ return fTZfmtCacheEntry->tzfmt->parse(style, text, pos, tzID, timeType);
+}
+
+
+// ---------------------------------------------------
+// TimeZoneFormat base class
+// ---------------------------------------------------
+TimeZoneFormat::~TimeZoneFormat() {
+}
+
+TimeZone*
+TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UTimeZoneTimeType* timeType /*= NULL*/) const {
+ UnicodeString tzID;
+ parse(style, text, pos, tzID, timeType);
+ if (pos.getErrorIndex() < 0) {
+ return TimeZone::createTimeZone(tzID);
+ }
+ return NULL;
+}
+
+TimeZoneFormat* U_EXPORT2
+TimeZoneFormat::createInstance(const Locale& locale, UErrorCode& status) {
+ TimeZoneFormat* tzfmt = new TimeZoneFormatDelegate(locale, status);
+ if (U_SUCCESS(status) && tzfmt == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return tzfmt;
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.h
new file mode 100644
index 00000000000..0222e6ae0c2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tzfmt.h
@@ -0,0 +1,65 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef __TZFMT_H
+#define __TZFMT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/uloc.h"
+#include "unicode/unistr.h"
+#include "unicode/format.h"
+#include "unicode/timezone.h"
+#include "tznames.h"
+
+U_CDECL_BEGIN
+
+typedef enum UTimeZoneFormatStyle {
+ UTZFMT_STYLE_LOCATION,
+ UTZFMT_STYLE_GENERIC_LONG,
+ UTZFMT_STYLE_GENERIC_SHORT,
+ UTZFMT_STYLE_SPECIFIC_LONG,
+ UTZFMT_STYLE_SPECIFIC_SHORT,
+ UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED
+} UTimeZoneFormatStyle;
+
+typedef enum UTimeZoneTimeType {
+ UTZFMT_TIME_TYPE_UNKNOWN,
+ UTZFMT_TIME_TYPE_STANDARD,
+ UTZFMT_TIME_TYPE_DAYLIGHT
+} UTimeZoneTimeType;
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+class TimeZoneNames;
+
+class U_I18N_API TimeZoneFormat : public UMemory {
+public:
+ virtual ~TimeZoneFormat();
+
+ static TimeZoneFormat* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
+
+ virtual const TimeZoneNames* getTimeZoneNames() const = 0;
+
+ virtual UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
+ UnicodeString& name, UTimeZoneTimeType* timeType = NULL) const = 0;
+
+ virtual UnicodeString& parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UnicodeString& tzID, UTimeZoneTimeType* timeType = NULL) const = 0;
+
+ TimeZone* parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
+ UTimeZoneTimeType* timeType = NULL) const;
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.cpp
new file mode 100644
index 00000000000..8f28bb5db84
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.cpp
@@ -0,0 +1,1062 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tzgnames.h"
+
+#include "unicode/basictz.h"
+#include "unicode/locdspnm.h"
+#include "unicode/msgfmt.h"
+#include "unicode/rbtz.h"
+#include "unicode/simpletz.h"
+#include "unicode/vtzone.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "uhash.h"
+#include "uassert.h"
+#include "umutex.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+#include "zonemeta.h"
+#include "tznames_impl.h"
+#include "olsontz.h"
+
+U_NAMESPACE_BEGIN
+
+#define ZID_KEY_MAX 128
+
+static const char gZoneStrings[] = "zoneStrings";
+
+static const char gRegionFormatTag[] = "regionFormat";
+static const char gFallbackRegionFormatTag[] = "fallbackRegionFormat";
+static const char gFallbackFormatTag[] = "fallbackFormat";
+
+static const UChar gEmpty[] = {0x00};
+
+static const UChar gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
+static const UChar gDefFallbackRegionPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
+static const UChar gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
+
+static const double kDstCheckRange = (double)184*U_MILLIS_PER_DAY;
+
+
+
+U_CDECL_BEGIN
+
+typedef struct PartialLocationKey {
+ const UChar* tzID;
+ const UChar* mzID;
+ UBool isLong;
+} PartialLocationKey;
+
+/**
+ * Hash function for partial location name hash key
+ */
+static int32_t U_CALLCONV
+hashPartialLocationKey(const UHashTok key) {
+ // <tzID>&<mzID>#[L|S]
+ PartialLocationKey *p = (PartialLocationKey *)key.pointer;
+ UnicodeString str(p->tzID);
+ str.append((UChar)0x26)
+ .append(p->mzID)
+ .append((UChar)0x23)
+ .append((UChar)(p->isLong ? 0x4C : 0x53));
+ return uhash_hashUCharsN(str.getBuffer(), str.length());
+}
+
+/**
+ * Comparer for partial location name hash key
+ */
+static UBool U_CALLCONV
+comparePartialLocationKey(const UHashTok key1, const UHashTok key2) {
+ PartialLocationKey *p1 = (PartialLocationKey *)key1.pointer;
+ PartialLocationKey *p2 = (PartialLocationKey *)key2.pointer;
+
+ if (p1 == p2) {
+ return TRUE;
+ }
+ if (p1 == NULL || p2 == NULL) {
+ return FALSE;
+ }
+ // We just check identity of tzID/mzID
+ return (p1->tzID == p2->tzID && p1->mzID == p2->mzID && p1->isLong == p2->isLong);
+}
+
+/**
+ * Deleter for GNameInfo
+ */
+static void U_CALLCONV
+deleteGNameInfo(void *obj) {
+ uprv_free(obj);
+}
+
+/**
+ * GNameInfo stores zone name information in the local trie
+ */
+typedef struct GNameInfo {
+ UTimeZoneGenericNameType type;
+ const UChar* tzID;
+} ZNameInfo;
+
+/**
+ * GMatchInfo stores zone name match information used by find method
+ */
+typedef struct GMatchInfo {
+ const GNameInfo* gnameInfo;
+ int32_t matchLength;
+ UTimeZoneTimeType timeType;
+} ZMatchInfo;
+
+U_CDECL_END
+
+// ---------------------------------------------------
+// The class stores time zone generic name match information
+// ---------------------------------------------------
+TimeZoneGenericNameMatchInfo::TimeZoneGenericNameMatchInfo(UVector* matches)
+: fMatches(matches) {
+}
+
+TimeZoneGenericNameMatchInfo::~TimeZoneGenericNameMatchInfo() {
+ if (fMatches != NULL) {
+ delete fMatches;
+ }
+}
+
+int32_t
+TimeZoneGenericNameMatchInfo::size() const {
+ if (fMatches == NULL) {
+ return 0;
+ }
+ return fMatches->size();
+}
+
+UTimeZoneGenericNameType
+TimeZoneGenericNameMatchInfo::getGenericNameType(int32_t index) const {
+ GMatchInfo *minfo = (GMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL) {
+ return static_cast<UTimeZoneGenericNameType>(minfo->gnameInfo->type);
+ }
+ return UTZGNM_UNKNOWN;
+}
+
+int32_t
+TimeZoneGenericNameMatchInfo::getMatchLength(int32_t index) const {
+ ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL) {
+ return minfo->matchLength;
+ }
+ return -1;
+}
+
+UnicodeString&
+TimeZoneGenericNameMatchInfo::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
+ GMatchInfo *minfo = (GMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL && minfo->gnameInfo->tzID != NULL) {
+ tzID.setTo(TRUE, minfo->gnameInfo->tzID, -1);
+ } else {
+ tzID.setToBogus();
+ }
+ return tzID;
+}
+
+// ---------------------------------------------------
+// GNameSearchHandler
+// ---------------------------------------------------
+class GNameSearchHandler : public TextTrieMapSearchResultHandler {
+public:
+ GNameSearchHandler(uint32_t types);
+ virtual ~GNameSearchHandler();
+
+ UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
+ UVector* getMatches(int32_t& maxMatchLen);
+
+private:
+ uint32_t fTypes;
+ UVector* fResults;
+ int32_t fMaxMatchLen;
+};
+
+GNameSearchHandler::GNameSearchHandler(uint32_t types)
+: fTypes(types), fResults(NULL), fMaxMatchLen(0) {
+}
+
+GNameSearchHandler::~GNameSearchHandler() {
+ if (fResults != NULL) {
+ delete fResults;
+ }
+}
+
+UBool
+GNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (node->hasValues()) {
+ int32_t valuesCount = node->countValues();
+ for (int32_t i = 0; i < valuesCount; i++) {
+ GNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
+ if (nameinfo == NULL) {
+ break;
+ }
+ if ((nameinfo->type & fTypes) != 0) {
+ // matches a requested type
+ if (fResults == NULL) {
+ fResults = new UVector(uhash_freeBlock, NULL, status);
+ if (fResults == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ if (U_SUCCESS(status)) {
+ GMatchInfo *gmatch = (GMatchInfo *)uprv_malloc(sizeof(GMatchInfo));
+ if (gmatch == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ // add the match to the vector
+ gmatch->gnameInfo = nameinfo;
+ gmatch->matchLength = matchLength;
+ gmatch->timeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ fResults->addElement(gmatch, status);
+ if (U_FAILURE(status)) {
+ uprv_free(gmatch);
+ } else {
+ if (matchLength > fMaxMatchLen) {
+ fMaxMatchLen = matchLength;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+UVector*
+GNameSearchHandler::getMatches(int32_t& maxMatchLen) {
+ // give the ownership to the caller
+ UVector *results = fResults;
+ maxMatchLen = fMaxMatchLen;
+
+ // reset
+ fResults = NULL;
+ fMaxMatchLen = 0;
+ return results;
+}
+
+// ---------------------------------------------------
+// TimeZoneGenericNames
+//
+// TimeZoneGenericNames is parallel to TimeZoneNames,
+// but handles run-time generated time zone names.
+// This is the main part of this module.
+// ---------------------------------------------------
+TimeZoneGenericNames::TimeZoneGenericNames(const Locale& locale, UErrorCode& status)
+: fLocale(locale),
+ fLock(NULL),
+ fTimeZoneNames(NULL),
+ fLocationNamesMap(NULL),
+ fPartialLocationNamesMap(NULL),
+ fRegionFormat(NULL),
+ fFallbackRegionFormat(NULL),
+ fFallbackFormat(NULL),
+ fLocaleDisplayNames(NULL),
+ fStringPool(status),
+ fGNamesTrie(TRUE, deleteGNameInfo),
+ fGNamesTrieFullyLoaded(FALSE) {
+ initialize(locale, status);
+}
+
+TimeZoneGenericNames::~TimeZoneGenericNames() {
+ cleanup();
+ umtx_destroy(&fLock);
+}
+
+void
+TimeZoneGenericNames::initialize(const Locale& locale, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // TimeZoneNames
+ fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Initialize format patterns
+ UnicodeString rpat(TRUE, gDefRegionPattern, -1);
+ UnicodeString frpat(TRUE, gDefFallbackRegionPattern, -1);
+ UnicodeString fpat(TRUE, gDefFallbackPattern, -1);
+
+ UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning..
+ UResourceBundle *zoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
+ zoneStrings = ures_getByKeyWithFallback(zoneStrings, gZoneStrings, zoneStrings, &tmpsts);
+
+ if (U_SUCCESS(tmpsts)) {
+ const UChar *regionPattern = ures_getStringByKeyWithFallback(zoneStrings, gRegionFormatTag, NULL, &tmpsts);
+ if (U_SUCCESS(tmpsts) && u_strlen(regionPattern) > 0) {
+ rpat.setTo(regionPattern);
+ }
+ tmpsts = U_ZERO_ERROR;
+ const UChar *fallbackRegionPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackRegionFormatTag, NULL, &tmpsts);
+ if (U_SUCCESS(tmpsts) && u_strlen(fallbackRegionPattern) > 0) {
+ frpat.setTo(fallbackRegionPattern);
+ }
+ tmpsts = U_ZERO_ERROR;
+ const UChar *fallbackPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackFormatTag, NULL, &tmpsts);
+ if (U_SUCCESS(tmpsts) && u_strlen(fallbackPattern) > 0) {
+ fpat.setTo(fallbackPattern);
+ }
+ }
+ ures_close(zoneStrings);
+
+ fRegionFormat = new MessageFormat(rpat, status);
+ if (fRegionFormat == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ fFallbackRegionFormat = new MessageFormat(frpat, status);
+ if (fFallbackRegionFormat == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ fFallbackFormat = new MessageFormat(fpat, status);
+ if (fFallbackFormat == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ cleanup();
+ return;
+ }
+
+ // locale display names
+ fLocaleDisplayNames = LocaleDisplayNames::createInstance(locale);
+
+ // hash table for names - no key/value deleters
+ fLocationNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ cleanup();
+ return;
+ }
+
+ fPartialLocationNamesMap = uhash_open(hashPartialLocationKey, comparePartialLocationKey, NULL, &status);
+ if (U_FAILURE(status)) {
+ cleanup();
+ return;
+ }
+ uhash_setKeyDeleter(fPartialLocationNamesMap, uhash_freeBlock);
+ // no value deleter
+
+ // target region
+ const char* region = fLocale.getCountry();
+ int32_t regionLen = uprv_strlen(region);
+ if (regionLen == 0) {
+ char loc[ULOC_FULLNAME_CAPACITY];
+ uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
+
+ regionLen = uloc_getCountry(loc, fTargetRegion, sizeof(fTargetRegion), &status);
+ if (U_SUCCESS(status)) {
+ fTargetRegion[regionLen] = 0;
+ } else {
+ cleanup();
+ return;
+ }
+ } else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
+ uprv_strcpy(fTargetRegion, region);
+ } else {
+ fTargetRegion[0] = 0;
+ }
+
+ // preload generic names for the default zone
+ TimeZone *tz = TimeZone::createDefault();
+ const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
+ if (tzID != NULL) {
+ loadStrings(UnicodeString(tzID));
+ }
+ delete tz;
+}
+
+void
+TimeZoneGenericNames::cleanup() {
+ if (fRegionFormat != NULL) {
+ delete fRegionFormat;
+ }
+ if (fFallbackRegionFormat != NULL) {
+ delete fFallbackRegionFormat;
+ }
+ if (fFallbackFormat != NULL) {
+ delete fFallbackFormat;
+ }
+ if (fLocaleDisplayNames != NULL) {
+ delete fLocaleDisplayNames;
+ }
+ if (fTimeZoneNames != NULL) {
+ delete fTimeZoneNames;
+ }
+
+ uhash_close(fLocationNamesMap);
+ uhash_close(fPartialLocationNamesMap);
+}
+
+UnicodeString&
+TimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
+ name.setToBogus();
+ switch (type) {
+ case UTZGNM_LOCATION:
+ {
+ const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
+ if (tzCanonicalID != NULL) {
+ getGenericLocationName(UnicodeString(tzCanonicalID), name);
+ }
+ }
+ break;
+ case UTZGNM_LONG:
+ case UTZGNM_SHORT:
+ formatGenericNonLocationName(tz, type, date, name);
+ if (name.isEmpty()) {
+ const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
+ if (tzCanonicalID != NULL) {
+ getGenericLocationName(UnicodeString(tzCanonicalID), name);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return name;
+}
+
+UnicodeString&
+TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
+ if (tzCanonicalID.isEmpty()) {
+ name.setToBogus();
+ return name;
+ }
+
+ const UChar *locname = NULL;
+ TimeZoneGenericNames *nonConstThis = const_cast<TimeZoneGenericNames *>(this);
+ umtx_lock(&nonConstThis->fLock);
+ {
+ locname = nonConstThis->getGenericLocationName(tzCanonicalID);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (locname == NULL) {
+ name.setToBogus();
+ } else {
+ name.setTo(TRUE, locname, -1);
+ }
+
+ return name;
+}
+
+/*
+ * This method updates the cache and must be called with a lock
+ */
+const UChar*
+TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID) {
+ U_ASSERT(!tzCanonicalID.isEmpty());
+ if (tzCanonicalID.length() > ZID_KEY_MAX) {
+ return NULL;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UChar tzIDKey[ZID_KEY_MAX + 1];
+ int32_t tzIDKeyLen = tzCanonicalID.extract(tzIDKey, ZID_KEY_MAX + 1, status);
+ U_ASSERT(status == U_ZERO_ERROR); // already checked length above
+ tzIDKey[tzIDKeyLen] = 0;
+
+ const UChar *locname = (const UChar *)uhash_get(fLocationNamesMap, tzIDKey);
+
+ if (locname != NULL) {
+ // gEmpty indicate the name is not available
+ if (locname == gEmpty) {
+ return NULL;
+ }
+ return locname;
+ }
+
+ // Construct location name
+ UnicodeString name;
+ UBool isSingleCountry = FALSE;
+ UnicodeString usCountryCode;
+ ZoneMeta::getSingleCountry(tzCanonicalID, usCountryCode);
+ if (!usCountryCode.isEmpty()) {
+ isSingleCountry = TRUE;
+ } else {
+ ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode);
+ }
+
+ if (!usCountryCode.isEmpty()) {
+ char countryCode[ULOC_COUNTRY_CAPACITY];
+ U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY);
+ int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV);
+ countryCode[ccLen] = 0;
+
+ UnicodeString country;
+ fLocaleDisplayNames->regionDisplayName(countryCode, country);
+
+ // Format
+ FieldPosition fpos;
+ if (isSingleCountry) {
+ // If the zone is only one zone in the country, do not add city
+ Formattable param[] = {
+ Formattable(country)
+ };
+ fRegionFormat->format(param, 1, name, fpos, status);
+ } else {
+ // getExemplarLocationName should retur non-empty string
+ // if the time zone is associated with a region
+ UnicodeString city;
+ fTimeZoneNames->getExemplarLocationName(tzCanonicalID, city);
+
+ Formattable params[] = {
+ Formattable(city),
+ Formattable(country)
+ };
+ fFallbackRegionFormat->format(params, 2, name, fpos, status);
+ }
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ }
+
+ locname = name.isEmpty() ? NULL : fStringPool.get(name, status);
+ if (U_SUCCESS(status)) {
+ // Cache the result
+ const UChar* cacheID = ZoneMeta::findTimeZoneID(tzCanonicalID);
+ U_ASSERT(cacheID != NULL);
+ if (locname == NULL) {
+ // gEmpty to indicate - no location name available
+ uhash_put(fLocationNamesMap, (void *)cacheID, (void *)gEmpty, &status);
+ } else {
+ uhash_put(fLocationNamesMap, (void *)cacheID, (void *)locname, &status);
+ if (U_FAILURE(status)) {
+ locname = NULL;
+ } else {
+ // put the name info into the trie
+ GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo));
+ if (nameinfo != NULL) {
+ nameinfo->type = UTZGNM_LOCATION;
+ nameinfo->tzID = cacheID;
+ fGNamesTrie.put(locname, nameinfo, status);
+ }
+ }
+ }
+ }
+
+ return locname;
+}
+
+UnicodeString&
+TimeZoneGenericNames::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
+ U_ASSERT(type == UTZGNM_LONG || type == UTZGNM_SHORT);
+ name.setToBogus();
+
+ const UChar* uID = ZoneMeta::getCanonicalCLDRID(tz);
+ if (uID == NULL) {
+ return name;
+ }
+
+ UnicodeString tzID(uID);
+
+ // Try to get a name from time zone first
+ UTimeZoneNameType nameType = (type == UTZGNM_LONG) ? UTZNM_LONG_GENERIC : UTZNM_SHORT_GENERIC;
+ fTimeZoneNames->getTimeZoneDisplayName(tzID, nameType, name);
+
+ if (!name.isEmpty()) {
+ return name;
+ }
+
+ // Try meta zone
+ UnicodeString mzID;
+ fTimeZoneNames->getMetaZoneID(tzID, date, mzID);
+ if (!mzID.isEmpty()) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool useStandard = FALSE;
+ int32_t raw, sav;
+
+ tz.getOffset(date, FALSE, raw, sav, status);
+ if (U_FAILURE(status)) {
+ return name;
+ }
+
+ if (sav == 0) {
+ useStandard = TRUE;
+
+ TimeZone *tmptz = tz.clone();
+ // Check if the zone actually uses daylight saving time around the time
+ BasicTimeZone *btz = NULL;
+ if (dynamic_cast<OlsonTimeZone *>(tmptz) != NULL
+ || dynamic_cast<SimpleTimeZone *>(tmptz) != NULL
+ || dynamic_cast<RuleBasedTimeZone *>(tmptz) != NULL
+ || dynamic_cast<VTimeZone *>(tmptz) != NULL) {
+ btz = (BasicTimeZone*)tmptz;
+ }
+
+ if (btz != NULL) {
+ TimeZoneTransition before;
+ UBool beforTrs = btz->getPreviousTransition(date, TRUE, before);
+ if (beforTrs
+ && (date - before.getTime() < kDstCheckRange)
+ && before.getFrom()->getDSTSavings() != 0) {
+ useStandard = FALSE;
+ } else {
+ TimeZoneTransition after;
+ UBool afterTrs = btz->getNextTransition(date, FALSE, after);
+ if (afterTrs
+ && (after.getTime() - date < 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(date - kDstCheckRange, FALSE, raw, sav, status);
+ if (sav != 0) {
+ useStandard = FALSE;
+ } else {
+ tmptz->getOffset(date + kDstCheckRange, FALSE, raw, sav, status);
+ if (sav != 0){
+ useStandard = FALSE;
+ }
+ }
+ if (U_FAILURE(status)) {
+ delete tmptz;
+ return name;
+ }
+ }
+ delete tmptz;
+ }
+ if (useStandard) {
+ UTimeZoneNameType stdNameType = (nameType == UTZNM_LONG_GENERIC)
+ ? UTZNM_LONG_STANDARD : UTZNM_SHORT_STANDARD_COMMONLY_USED;
+ UnicodeString stdName;
+ fTimeZoneNames->getDisplayName(tzID, stdNameType, date, stdName);
+ if (!stdName.isEmpty()) {
+ name.setTo(stdName);
+
+ // TODO: revisit this issue later
+ // In CLDR, a same display name is used for both generic and standard
+ // for some meta zones in some locales. This looks like a data bugs.
+ // For now, we check if the standard name is different from its generic
+ // name below.
+ UnicodeString mzGenericName;
+ fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzGenericName);
+ if (stdName.caseCompare(mzGenericName, 0) == 0) {
+ name.setToBogus();
+ }
+ }
+ }
+ if (name.isEmpty()) {
+ // Get a name from meta zone
+ UnicodeString mzName;
+ fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzName);
+ if (!mzName.isEmpty()) {
+ // Check if we need to use a partial location format.
+ // This check is done by comparing offset with the meta zone's
+ // golden zone at the given date.
+ UnicodeString goldenID;
+ fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, goldenID);
+ if (!goldenID.isEmpty() && goldenID != tzID) {
+ TimeZone *goldenZone = TimeZone::createTimeZone(goldenID);
+ int32_t raw1, sav1;
+
+ // Check offset in the golden zone with wall time.
+ // With getOffset(date, false, offsets1),
+ // you may get incorrect results because of time overlap at DST->STD
+ // transition.
+ goldenZone->getOffset(date + raw + sav, TRUE, raw1, sav1, status);
+ delete goldenZone;
+ if (U_SUCCESS(status)) {
+ if (raw != raw1 || sav != sav1) {
+ // Now we need to use a partial location format
+ getPartialLocationName(tzID, mzID, (nameType == UTZNM_LONG_GENERIC), mzName, name);
+ } else {
+ name.setTo(mzName);
+ }
+ }
+ } else {
+ name.setTo(mzName);
+ }
+ }
+ }
+ }
+ return name;
+}
+
+UnicodeString&
+TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
+ const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
+ UnicodeString& name) const {
+ name.setToBogus();
+ if (tzCanonicalID.isEmpty() || mzID.isEmpty() || mzDisplayName.isEmpty()) {
+ return name;
+ }
+
+ const UChar *uplname = NULL;
+ TimeZoneGenericNames *nonConstThis = const_cast<TimeZoneGenericNames *>(this);
+ umtx_lock(&nonConstThis->fLock);
+ {
+ uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (uplname == NULL) {
+ name.setToBogus();
+ } else {
+ name.setTo(TRUE, uplname, -1);
+ }
+ return name;
+}
+
+/*
+ * This method updates the cache and must be called with a lock
+ */
+const UChar*
+TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
+ const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName) {
+ U_ASSERT(!tzCanonicalID.isEmpty());
+ U_ASSERT(!mzID.isEmpty());
+ U_ASSERT(!mzDisplayName.isEmpty());
+
+ PartialLocationKey key;
+ key.tzID = ZoneMeta::findTimeZoneID(tzCanonicalID);
+ key.mzID = ZoneMeta::findMetaZoneID(mzID);
+ key.isLong = isLong;
+ U_ASSERT(key.tzID != NULL && key.mzID != NULL);
+
+ const UChar* uplname = (const UChar*)uhash_get(fPartialLocationNamesMap, (void *)&key);
+ if (uplname != NULL) {
+ return uplname;
+ }
+
+ UnicodeString location;
+ UnicodeString usCountryCode;
+ ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode);
+ if (!usCountryCode.isEmpty()) {
+ char countryCode[ULOC_COUNTRY_CAPACITY];
+ U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY);
+ int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV);
+ countryCode[ccLen] = 0;
+
+ UnicodeString regionalGolden;
+ fTimeZoneNames->getReferenceZoneID(mzID, countryCode, regionalGolden);
+ if (tzCanonicalID == regionalGolden) {
+ // Use country name
+ fLocaleDisplayNames->regionDisplayName(countryCode, location);
+ } else {
+ // Otherwise, use exemplar city name
+ fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
+ }
+ } else {
+ fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
+ if (location.isEmpty()) {
+ // This could happen when the time zone is not associated with a country,
+ // and its ID is not hierarchical, for example, CST6CDT.
+ // We use the canonical ID itself as the location for this case.
+ location.setTo(tzCanonicalID);
+ }
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString name;
+
+ FieldPosition fpos;
+ Formattable param[] = {
+ Formattable(location),
+ Formattable(mzDisplayName)
+ };
+ fFallbackFormat->format(param, 2, name, fpos, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ uplname = fStringPool.get(name, status);
+ if (U_SUCCESS(status)) {
+ // Add the name to cache
+ PartialLocationKey* cacheKey = (PartialLocationKey *)uprv_malloc(sizeof(PartialLocationKey));
+ if (cacheKey != NULL) {
+ cacheKey->tzID = key.tzID;
+ cacheKey->mzID = key.mzID;
+ cacheKey->isLong = key.isLong;
+ uhash_put(fPartialLocationNamesMap, (void *)cacheKey, (void *)uplname, &status);
+ if (U_FAILURE(status)) {
+ uprv_free(cacheKey);
+ } else {
+ // put the name to the local trie as well
+ GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo));
+ if (nameinfo != NULL) {
+ nameinfo->type = isLong ? UTZGNM_LONG : UTZGNM_SHORT;
+ nameinfo->tzID = key.tzID;
+ fGNamesTrie.put(uplname, nameinfo, status);
+ }
+ }
+ }
+ }
+ return uplname;
+}
+
+/*
+ * This method updates the cache and must be called with a lock,
+ * except initializer.
+ */
+void
+TimeZoneGenericNames::loadStrings(const UnicodeString& tzCanonicalID) {
+ // load the generic location name
+ getGenericLocationName(tzCanonicalID);
+
+ // partial location names
+ UErrorCode status = U_ZERO_ERROR;
+
+ const UnicodeString *mzID;
+ UnicodeString goldenID;
+ UnicodeString mzGenName;
+ UTimeZoneNameType genNonLocTypes[] = {
+ UTZNM_LONG_GENERIC, UTZNM_SHORT_GENERIC,
+ UTZNM_UNKNOWN /*terminator*/
+ };
+
+ StringEnumeration *mzIDs = fTimeZoneNames->getAvailableMetaZoneIDs(tzCanonicalID, status);
+ while ((mzID = mzIDs->snext(status))) {
+ if (U_FAILURE(status)) {
+ break;
+ }
+ // if this time zone is not the golden zone of the meta zone,
+ // partial location name (such as "PT (Los Angeles)") might be
+ // available.
+ fTimeZoneNames->getReferenceZoneID(*mzID, fTargetRegion, goldenID);
+ if (tzCanonicalID != goldenID) {
+ for (int32_t i = 0; genNonLocTypes[i] != UTZNM_UNKNOWN; i++) {
+ fTimeZoneNames->getMetaZoneDisplayName(*mzID, genNonLocTypes[i], mzGenName);
+ if (!mzGenName.isEmpty()) {
+ // getPartialLocationName formats a name and put it into the trie
+ getPartialLocationName(tzCanonicalID, *mzID,
+ (genNonLocTypes[i] == UTZNM_LONG_GENERIC), mzGenName);
+ }
+ }
+ }
+ }
+ if (mzIDs != NULL) {
+ delete mzIDs;
+ }
+}
+
+int32_t
+TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
+ UnicodeString& tzID, UTimeZoneTimeType& timeType, UErrorCode& status) const {
+ timeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ tzID.setToBogus();
+
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ // Find matches in the TimeZoneNames first
+ TimeZoneNameMatchInfo *tznamesMatches = findTimeZoneNames(text, start, types, status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ int32_t bestMatchLen = 0;
+ UTimeZoneTimeType bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ UnicodeString bestMatchTzID;
+ UBool isLongStandard = FALSE; // workaround - see the comments below
+
+ if (tznamesMatches != NULL) {
+ UnicodeString mzID;
+ for (int32_t i = 0; i < tznamesMatches->size(); i++) {
+ int32_t len = tznamesMatches->getMatchLength(i);
+ if (len > bestMatchLen) {
+ bestMatchLen = len;
+ tznamesMatches->getTimeZoneID(i, bestMatchTzID);
+ if (bestMatchTzID.isEmpty()) {
+ // name for a meta zone
+ tznamesMatches->getMetaZoneID(i, mzID);
+ U_ASSERT(mzID.length() > 0);
+ fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, bestMatchTzID);
+ }
+ UTimeZoneNameType nameType = tznamesMatches->getNameType(i);
+ switch (nameType) {
+ case UTZNM_LONG_STANDARD:
+ isLongStandard = TRUE;
+ case UTZNM_SHORT_STANDARD_COMMONLY_USED:
+ case UTZNM_SHORT_STANDARD: // this one is never used for generic, but just in case
+ bestMatchTimeType = UTZFMT_TIME_TYPE_STANDARD;
+ break;
+ case UTZNM_LONG_DAYLIGHT:
+ case UTZNM_SHORT_DAYLIGHT_COMMONLY_USED:
+ case UTZNM_SHORT_DAYLIGHT: // this one is never used for generic, but just in case
+ bestMatchTimeType = UTZFMT_TIME_TYPE_DAYLIGHT;
+ break;
+ default:
+ bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ }
+ }
+ }
+ delete tznamesMatches;
+
+ if (bestMatchLen == (text.length() - start)) {
+ // Full match
+
+ //tzID.setTo(bestMatchTzID);
+ //timeType = bestMatchTimeType;
+ //return bestMatchLen;
+
+ // TODO Some time zone uses a same name for the long standard name
+ // and the location name. When the match is a long standard name,
+ // then we need to check if the name is same with the location name.
+ // This is probably a data error or a design bug.
+ if (!isLongStandard) {
+ tzID.setTo(bestMatchTzID);
+ timeType = bestMatchTimeType;
+ return bestMatchLen;
+ }
+ }
+ }
+
+ // Find matches in the local trie
+ TimeZoneGenericNameMatchInfo *localMatches = findLocal(text, start, types, status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ if (localMatches != NULL) {
+ for (int32_t i = 0; i < localMatches->size(); i++) {
+ int32_t len = localMatches->getMatchLength(i);
+
+ // TODO See the above TODO. We use len >= bestMatchLen
+ // because of the long standard/location name collision
+ // problem. If it is also a location name, carrying
+ // timeType = UTZFMT_TIME_TYPE_STANDARD will cause a
+ // problem in SimpleDateFormat
+ if (len >= bestMatchLen) {
+ bestMatchLen = localMatches->getMatchLength(i);
+ bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN; // because generic
+ localMatches->getTimeZoneID(i, bestMatchTzID);
+ }
+ }
+ delete localMatches;
+ }
+
+ if (bestMatchLen > 0) {
+ timeType = bestMatchTimeType;
+ tzID.setTo(bestMatchTzID);
+ }
+ return bestMatchLen;
+}
+
+TimeZoneGenericNameMatchInfo*
+TimeZoneGenericNames::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
+ GNameSearchHandler handler(types);
+
+ TimeZoneGenericNames *nonConstThis = const_cast<TimeZoneGenericNames *>(this);
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ TimeZoneGenericNameMatchInfo *gmatchInfo = NULL;
+
+ int32_t maxLen = 0;
+ UVector *results = handler.getMatches(maxLen);
+ if (results != NULL && ((maxLen == (text.length() - start)) || fGNamesTrieFullyLoaded)) {
+ // perfect match
+ gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
+ if (gmatchInfo == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete results;
+ return NULL;
+ }
+ return gmatchInfo;
+ }
+
+ if (results != NULL) {
+ delete results;
+ }
+
+ // All names are not yet loaded into the local trie.
+ // Load all available names into the trie. This could be very heavy.
+ umtx_lock(&nonConstThis->fLock);
+ {
+ if (!fGNamesTrieFullyLoaded) {
+ StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ const UnicodeString *tzID;
+ while ((tzID = tzIDs->snext(status))) {
+ if (U_FAILURE(status)) {
+ break;
+ }
+ nonConstThis->loadStrings(*tzID);
+ }
+ }
+ if (tzIDs != NULL) {
+ delete tzIDs;
+ }
+
+ if (U_SUCCESS(status)) {
+ nonConstThis->fGNamesTrieFullyLoaded = TRUE;
+ }
+ }
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ // now try it again
+ fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ results = handler.getMatches(maxLen);
+ if (results != NULL && maxLen > 0) {
+ gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
+ if (gmatchInfo == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete results;
+ return NULL;
+ }
+ }
+
+ return gmatchInfo;
+}
+
+TimeZoneNameMatchInfo*
+TimeZoneGenericNames::findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
+ TimeZoneNameMatchInfo *matchInfo = NULL;
+
+ // Check if the target name typs is really in the TimeZoneNames
+ uint32_t nameTypes = 0;
+ if (types & UTZGNM_LONG) {
+ nameTypes |= (UTZNM_LONG_GENERIC | UTZNM_LONG_STANDARD);
+ }
+ if (types & UTZGNM_SHORT) {
+ nameTypes |= (UTZNM_SHORT_GENERIC | UTZNM_SHORT_STANDARD_COMMONLY_USED);
+ }
+
+ if (types) {
+ // Find matches in the TimeZoneNames
+ matchInfo = fTimeZoneNames->find(text, start, nameTypes, status);
+ }
+
+ return matchInfo;
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.h b/Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.h
new file mode 100644
index 00000000000..49a471f840c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tzgnames.h
@@ -0,0 +1,115 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef __TZGNAMES_H
+#define __TZGNAMES_H
+
+/**
+ * \file
+ * \brief C API: Time zone generic names classe
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/locid.h"
+#include "unicode/timezone.h"
+#include "unicode/unistr.h"
+#include "tznames.h"
+#include "tznames_impl.h"
+#include "tzfmt.h"
+#include "uhash.h"
+#include "umutex.h"
+
+U_CDECL_BEGIN
+
+typedef enum UTimeZoneGenericNameType {
+ UTZGNM_UNKNOWN = 0x00,
+ UTZGNM_LOCATION = 0x01,
+ UTZGNM_LONG = 0x02,
+ UTZGNM_SHORT = 0x04
+} UTimeZoneGenericNameType;
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+class LocaleDisplayNames;
+class MessageFormat;
+class TimeZone;
+
+class TimeZoneGenericNameMatchInfo : public UMemory {
+public:
+ TimeZoneGenericNameMatchInfo(UVector* matches);
+ ~TimeZoneGenericNameMatchInfo();
+
+ int32_t size() const;
+ UTimeZoneGenericNameType getGenericNameType(int32_t index) const;
+ int32_t getMatchLength(int32_t index) const;
+ UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
+
+private:
+ UVector* fMatches; // vector of MatchEntry
+};
+
+class U_I18N_API TimeZoneGenericNames : public UMemory {
+public:
+ TimeZoneGenericNames(const Locale& locale, UErrorCode& status);
+ virtual ~TimeZoneGenericNames();
+
+ UnicodeString& getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
+ UDate date, UnicodeString& name) const;
+
+ UnicodeString& getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const;
+
+ int32_t findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
+ UnicodeString& tzID, UTimeZoneTimeType& timeType, UErrorCode& status) const;
+
+private:
+ Locale fLocale;
+ UMTX fLock;
+ const TimeZoneNames* fTimeZoneNames;
+ UHashtable* fLocationNamesMap;
+ UHashtable* fPartialLocationNamesMap;
+
+ MessageFormat* fRegionFormat;
+ MessageFormat* fFallbackRegionFormat;
+ MessageFormat* fFallbackFormat;
+
+ LocaleDisplayNames* fLocaleDisplayNames;
+ ZNStringPool fStringPool;
+
+ TextTrieMap fGNamesTrie;
+ UBool fGNamesTrieFullyLoaded;
+
+ char fTargetRegion[ULOC_COUNTRY_CAPACITY];
+
+ void initialize(const Locale& locale, UErrorCode& status);
+ void cleanup();
+
+ void loadStrings(const UnicodeString& tzCanonicalID);
+
+ const UChar* getGenericLocationName(const UnicodeString& tzCanonicalID);
+
+ UnicodeString& formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type,
+ UDate date, UnicodeString& name) const;
+
+ UnicodeString& getPartialLocationName(const UnicodeString& tzCanonicalID,
+ const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
+ UnicodeString& name) const;
+
+ const UChar* getPartialLocationName(const UnicodeString& tzCanonicalID,
+ const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName);
+
+ TimeZoneGenericNameMatchInfo* findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
+
+ TimeZoneNameMatchInfo* findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
+};
+
+U_NAMESPACE_END
+#endif
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tznames.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tznames.cpp
new file mode 100644
index 00000000000..0adf95594ff
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tznames.cpp
@@ -0,0 +1,300 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tznames.h"
+#include "tznames_impl.h"
+
+#include "unicode/locid.h"
+#include "unicode/uenum.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uhash.h"
+#include "umutex.h"
+
+
+U_NAMESPACE_BEGIN
+
+static const UChar gEtcPrefix[] = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
+static const int32_t gEtcPrefixLen = 4;
+static const UChar gSystemVPrefix[] = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
+static const int32_t gSystemVPrefixLen = 8;
+static const UChar gRiyadh8[] = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
+static const int32_t gRiyadh8Len = 7;
+
+// TimeZoneNames object cache handling
+static UMTX gTimeZoneNamesLock = NULL;
+static UHashtable *gTimeZoneNamesCache = NULL;
+static UBool gTimeZoneNamesCacheInitialized = FALSE;
+
+// Access count - incremented every time up to SWEEP_INTERVAL,
+// then reset to 0
+static int32_t gAccessCount = 0;
+
+// Interval for calling the cache sweep function - every 100 times
+#define SWEEP_INTERVAL 100
+
+// Cache expiration in millisecond. When a cached entry is no
+// longer referenced and exceeding this threshold since last
+// access time, then the cache entry will be deleted by the sweep
+// function. For now, 3 minutes.
+#define CACHE_EXPIRATION 180000.0
+
+typedef struct TimeZoneNamesCacheEntry {
+ TimeZoneNames* names;
+ int32_t refCount;
+ double lastAccess;
+} TimeZoneNamesCacheEntry;
+
+U_CDECL_BEGIN
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV timeZoneNames_cleanup(void)
+{
+ umtx_destroy(&gTimeZoneNamesLock);
+
+ if (gTimeZoneNamesCache != NULL) {
+ uhash_close(gTimeZoneNamesCache);
+ gTimeZoneNamesCache = NULL;
+ }
+ gTimeZoneNamesCacheInitialized = FALSE;
+ return TRUE;
+}
+
+/**
+ * Deleter for TimeZoneNamesCacheEntry
+ */
+static void U_CALLCONV
+deleteTimeZoneNamesCacheEntry(void *obj) {
+ icu::TimeZoneNamesCacheEntry *entry = (icu::TimeZoneNamesCacheEntry*)obj;
+ delete (icu::TimeZoneNamesImpl*) entry->names;
+ uprv_free(entry);
+}
+U_CDECL_END
+
+/**
+ * Function used for removing unreferrenced cache entries exceeding
+ * the expiration time. This function must be called with in the mutex
+ * block.
+ */
+static void sweepCache() {
+ int32_t pos = -1;
+ const UHashElement* elem;
+ double now = (double)uprv_getUTCtime();
+
+ while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) {
+ TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
+ if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
+ // delete this entry
+ uhash_removeElement(gTimeZoneNamesCache, elem);
+ }
+ }
+}
+
+class TimeZoneNamesDelegate : public TimeZoneNames {
+public:
+ TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status);
+ virtual ~TimeZoneNamesDelegate();
+
+ StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
+ StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
+ UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const;
+ UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const;
+
+ UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const;
+ UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const;
+
+ UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
+
+ TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
+private:
+ TimeZoneNamesCacheEntry* fTZnamesCacheEntry;
+};
+
+TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
+ UBool initialized;
+ UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized);
+ if (!initialized) {
+ // Create empty hashtable
+ umtx_lock(&gTimeZoneNamesLock);
+ {
+ if (!gTimeZoneNamesCacheInitialized) {
+ gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+ if (U_SUCCESS(status)) {
+ uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
+ uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
+ gTimeZoneNamesCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
+ }
+ }
+ }
+ umtx_unlock(&gTimeZoneNamesLock);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ // Check the cache, if not available, create new one and cache
+ TimeZoneNamesCacheEntry *cacheEntry = NULL;
+ umtx_lock(&gTimeZoneNamesLock);
+ {
+ const char *key = locale.getName();
+ cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
+ if (cacheEntry == NULL) {
+ TimeZoneNames *tznames = NULL;
+ char *newKey = NULL;
+
+ tznames = new TimeZoneNamesImpl(locale, status);
+ if (tznames == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_SUCCESS(status)) {
+ newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
+ if (newKey == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ uprv_strcpy(newKey, key);
+ }
+ }
+ if (U_SUCCESS(status)) {
+ cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
+ if (cacheEntry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ cacheEntry->names = tznames;
+ cacheEntry->refCount = 1;
+ cacheEntry->lastAccess = (double)uprv_getUTCtime();
+
+ uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ if (tznames != NULL) {
+ delete tznames;
+ }
+ if (newKey != NULL) {
+ uprv_free(newKey);
+ }
+ if (cacheEntry != NULL) {
+ uprv_free(cacheEntry);
+ }
+ cacheEntry = NULL;
+ }
+ } else {
+ // Update the reference count
+ cacheEntry->refCount++;
+ cacheEntry->lastAccess = (double)uprv_getUTCtime();
+ }
+ gAccessCount++;
+ if (gAccessCount >= SWEEP_INTERVAL) {
+ // sweep
+ sweepCache();
+ gAccessCount = 0;
+ }
+ }
+ umtx_unlock(&gTimeZoneNamesLock);
+
+ fTZnamesCacheEntry = cacheEntry;
+}
+
+TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
+ umtx_lock(&gTimeZoneNamesLock);
+ {
+ U_ASSERT(fTZnamesCacheEntry->refCount > 0);
+ // Just decrement the reference count
+ fTZnamesCacheEntry->refCount--;
+ }
+ umtx_unlock(&gTimeZoneNamesLock);
+}
+
+StringEnumeration*
+TimeZoneNamesDelegate::getAvailableMetaZoneIDs(UErrorCode& status) const {
+ return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(status);
+}
+
+StringEnumeration*
+TimeZoneNamesDelegate::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
+ return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(tzID, status);
+}
+
+UnicodeString&
+TimeZoneNamesDelegate::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
+ return fTZnamesCacheEntry->names->getMetaZoneID(tzID, date, mzID);
+}
+
+UnicodeString&
+TimeZoneNamesDelegate::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
+ return fTZnamesCacheEntry->names->getReferenceZoneID(mzID, region, tzID);
+}
+
+UnicodeString&
+TimeZoneNamesDelegate::getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const {
+ return fTZnamesCacheEntry->names->getMetaZoneDisplayName(mzID, type, name);
+}
+
+UnicodeString&
+TimeZoneNamesDelegate::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
+ return fTZnamesCacheEntry->names->getTimeZoneDisplayName(tzID, type, name);
+}
+
+UnicodeString&
+TimeZoneNamesDelegate::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
+ return fTZnamesCacheEntry->names->getExemplarLocationName(tzID, name);
+}
+
+TimeZoneNameMatchInfo*
+TimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
+ return fTZnamesCacheEntry->names->find(text, start, types, status);
+}
+
+
+
+TimeZoneNames*
+TimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
+ return new TimeZoneNamesDelegate(locale, status);
+}
+
+UnicodeString&
+TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
+ if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
+ || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
+ name.setToBogus();
+ return name;
+ }
+
+ int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
+ if (sep > 0 && sep + 1 < tzID.length()) {
+ name.setTo(tzID, sep + 1);
+ name.findAndReplace(UnicodeString((UChar)0x5f /* _ */),
+ UnicodeString((UChar)0x20 /* space */));
+ } else {
+ name.setToBogus();
+ }
+ return name;
+}
+
+UnicodeString&
+TimeZoneNames::getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const {
+ getTimeZoneDisplayName(tzID, type, name);
+ if (name.isEmpty()) {
+ UnicodeString mzID;
+ getMetaZoneID(tzID, date, mzID);
+ getMetaZoneDisplayName(mzID, type, name);
+ }
+ return name;
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tznames.h b/Build/source/libs/icu/icu-4.8.1/i18n/tznames.h
new file mode 100644
index 00000000000..0f281c63776
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tznames.h
@@ -0,0 +1,81 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef __TZNAMES_H
+#define __TZNAMES_H
+
+/**
+ * \file
+ * \brief C API: Time zone names class
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uloc.h"
+#include "unicode/unistr.h"
+
+U_CDECL_BEGIN
+
+typedef enum UTimeZoneNameType {
+ UTZNM_UNKNOWN = 0x00,
+ UTZNM_LONG_GENERIC = 0x01,
+ UTZNM_LONG_STANDARD = 0x02,
+ UTZNM_LONG_DAYLIGHT = 0x04,
+ UTZNM_SHORT_GENERIC = 0x08,
+ UTZNM_SHORT_STANDARD = 0x10,
+ UTZNM_SHORT_DAYLIGHT = 0x20,
+ UTZNM_SHORT_STANDARD_COMMONLY_USED = 0x40,
+ UTZNM_SHORT_DAYLIGHT_COMMONLY_USED = 0x80
+} UTimeZoneNameType;
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+class U_I18N_API TimeZoneNameMatchInfo : public UMemory {
+public:
+ virtual ~TimeZoneNameMatchInfo();
+
+ virtual int32_t size() const = 0;
+ virtual UTimeZoneNameType getNameType(int32_t index) const = 0;
+ virtual int32_t getMatchLength(int32_t index) const = 0;
+ virtual UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const = 0;
+ virtual UnicodeString& getMetaZoneID(int32_t index, UnicodeString& mzID) const = 0;
+};
+
+inline
+TimeZoneNameMatchInfo::~TimeZoneNameMatchInfo() {
+}
+
+class U_I18N_API TimeZoneNames : public UMemory {
+public:
+ virtual ~TimeZoneNames();
+
+ static TimeZoneNames* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
+
+ virtual StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const = 0;
+ virtual StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const = 0;
+
+ virtual UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const = 0;
+ virtual UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const = 0;
+
+ virtual UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const = 0;
+ virtual UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const = 0;
+
+ virtual UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
+ virtual UnicodeString& getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const;
+
+ virtual TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const = 0;
+};
+
+inline
+TimeZoneNames::~TimeZoneNames() {
+}
+
+U_NAMESPACE_END
+#endif
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.cpp
new file mode 100644
index 00000000000..5460eae973e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.cpp
@@ -0,0 +1,1426 @@
+/*
+*******************************************************************************
+* Copyright (C) 2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File TZNAMES_IMPL.CPP
+*
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ustring.h"
+#include "unicode/timezone.h"
+
+#include "tznames_impl.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+#include "zonemeta.h"
+#include "ucln_in.h"
+#include "uvector.h"
+#include "olsontz.h"
+
+
+U_NAMESPACE_BEGIN
+
+#define ZID_KEY_MAX 128
+#define MZ_PREFIX_LEN 5
+
+static const char gZoneStrings[] = "zoneStrings";
+static const char gMZPrefix[] = "meta:";
+
+static const char* KEYS[] = {"lg", "ls", "ld", "sg", "ss", "sd"};
+static const int32_t KEYS_SIZE = (sizeof KEYS / sizeof KEYS[0]);
+
+static const char gCuTag[] = "cu";
+static const char gEcTag[] = "ec";
+
+static const char EMPTY[] = "<empty>"; // place holder for empty ZNames/TZNames
+
+static const UTimeZoneNameType ALL_NAME_TYPES[] = {
+ UTZNM_LONG_GENERIC, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT,
+ UTZNM_SHORT_GENERIC, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT,
+ UTZNM_SHORT_STANDARD_COMMONLY_USED, UTZNM_SHORT_DAYLIGHT_COMMONLY_USED,
+ UTZNM_UNKNOWN // unknown as the last one
+};
+
+#define DEFAULT_CHARACTERNODE_CAPACITY 1
+
+// ---------------------------------------------------
+// CaracterNode class implementation
+// ---------------------------------------------------
+void CharacterNode::clear() {
+ uprv_memset(this, 0, sizeof(*this));
+}
+
+void CharacterNode::deleteValues(UObjectDeleter *valueDeleter) {
+ if (fValues == NULL) {
+ // Do nothing.
+ } else if (!fHasValuesVector) {
+ if (valueDeleter) {
+ valueDeleter(fValues);
+ }
+ } else {
+ delete (UVector *)fValues;
+ }
+}
+
+void
+CharacterNode::addValue(void *value, UObjectDeleter *valueDeleter, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ if (valueDeleter) {
+ valueDeleter(value);
+ }
+ return;
+ }
+ if (fValues == NULL) {
+ fValues = value;
+ } else {
+ // At least one value already.
+ if (!fHasValuesVector) {
+ // There is only one value so far, and not in a vector yet.
+ // Create a vector and add the old value.
+ UVector *values = new UVector(valueDeleter, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status);
+ if (U_FAILURE(status)) {
+ if (valueDeleter) {
+ valueDeleter(value);
+ }
+ return;
+ }
+ values->addElement(fValues, status);
+ fValues = values;
+ fHasValuesVector = TRUE;
+ }
+ // Add the new value.
+ ((UVector *)fValues)->addElement(value, status);
+ }
+}
+
+// ---------------------------------------------------
+// TextTrieMapSearchResultHandler class implementation
+// ---------------------------------------------------
+TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){
+}
+
+// ---------------------------------------------------
+// TextTrieMap class implementation
+// ---------------------------------------------------
+TextTrieMap::TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleter)
+: fIgnoreCase(ignoreCase), fNodes(NULL), fNodesCapacity(0), fNodesCount(0),
+ fLazyContents(NULL), fIsEmpty(TRUE), fValueDeleter(valueDeleter) {
+}
+
+TextTrieMap::~TextTrieMap() {
+ int32_t index;
+ for (index = 0; index < fNodesCount; ++index) {
+ fNodes[index].deleteValues(fValueDeleter);
+ }
+ uprv_free(fNodes);
+ if (fLazyContents != NULL) {
+ for (int32_t i=0; i<fLazyContents->size(); i+=2) {
+ if (fValueDeleter) {
+ fValueDeleter(fLazyContents->elementAt(i+1));
+ }
+ }
+ delete fLazyContents;
+ }
+}
+
+int32_t TextTrieMap::isEmpty() const {
+ // Use a separate field for fIsEmpty because it will remain unchanged once the
+ // Trie is built, while fNodes and fLazyContents change with the lazy init
+ // of the nodes structure. Trying to test the changing fields has
+ // thread safety complications.
+ return fIsEmpty;
+}
+
+
+// We defer actually building the TextTrieMap node structure until the first time a
+// search is performed. put() simply saves the parameters in case we do
+// eventually need to build it.
+//
+void
+TextTrieMap::put(const UnicodeString &key, void *value, ZNStringPool &sp, UErrorCode &status) {
+ const UChar *s = sp.get(key, status);
+ put(s, value, status);
+}
+
+// This method is for designed for a persistent key, such as string key stored in
+// resource bundle.
+void
+TextTrieMap::put(const UChar *key, void *value, UErrorCode &status) {
+ fIsEmpty = FALSE;
+ if (fLazyContents == NULL) {
+ fLazyContents = new UVector(status);
+ if (fLazyContents == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UChar *s = const_cast<UChar *>(key);
+ fLazyContents->addElement(s, status);
+ fLazyContents->addElement(value, status);
+}
+
+void
+TextTrieMap::putImpl(const UnicodeString &key, void *value, UErrorCode &status) {
+ if (fNodes == NULL) {
+ fNodesCapacity = 512;
+ fNodes = (CharacterNode *)uprv_malloc(fNodesCapacity * sizeof(CharacterNode));
+ fNodes[0].clear(); // Init root node.
+ fNodesCount = 1;
+ }
+
+ UnicodeString foldedKey;
+ const UChar *keyBuffer;
+ int32_t keyLength;
+ if (fIgnoreCase) {
+ // Ok to use fastCopyFrom() because we discard the copy when we return.
+ foldedKey.fastCopyFrom(key).foldCase();
+ keyBuffer = foldedKey.getBuffer();
+ keyLength = foldedKey.length();
+ } else {
+ keyBuffer = key.getBuffer();
+ keyLength = key.length();
+ }
+
+ CharacterNode *node = fNodes;
+ int32_t index;
+ for (index = 0; index < keyLength; ++index) {
+ node = addChildNode(node, keyBuffer[index], status);
+ }
+ node->addValue(value, fValueDeleter, status);
+}
+
+UBool
+TextTrieMap::growNodes() {
+ if (fNodesCapacity == 0xffff) {
+ return FALSE; // We use 16-bit node indexes.
+ }
+ int32_t newCapacity = fNodesCapacity + 1000;
+ if (newCapacity > 0xffff) {
+ newCapacity = 0xffff;
+ }
+ CharacterNode *newNodes = (CharacterNode *)uprv_malloc(newCapacity * sizeof(CharacterNode));
+ if (newNodes == NULL) {
+ return FALSE;
+ }
+ uprv_memcpy(newNodes, fNodes, fNodesCount * sizeof(CharacterNode));
+ uprv_free(fNodes);
+ fNodes = newNodes;
+ fNodesCapacity = newCapacity;
+ return TRUE;
+}
+
+CharacterNode*
+TextTrieMap::addChildNode(CharacterNode *parent, UChar c, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ // Linear search of the sorted list of children.
+ uint16_t prevIndex = 0;
+ uint16_t nodeIndex = parent->fFirstChild;
+ while (nodeIndex > 0) {
+ CharacterNode *current = fNodes + nodeIndex;
+ UChar childCharacter = current->fCharacter;
+ if (childCharacter == c) {
+ return current;
+ } else if (childCharacter > c) {
+ break;
+ }
+ prevIndex = nodeIndex;
+ nodeIndex = current->fNextSibling;
+ }
+
+ // Ensure capacity. Grow fNodes[] if needed.
+ if (fNodesCount == fNodesCapacity) {
+ int32_t parentIndex = (int32_t)(parent - fNodes);
+ if (!growNodes()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ parent = fNodes + parentIndex;
+ }
+
+ // Insert a new child node with c in sorted order.
+ CharacterNode *node = fNodes + fNodesCount;
+ node->clear();
+ node->fCharacter = c;
+ node->fNextSibling = nodeIndex;
+ if (prevIndex == 0) {
+ parent->fFirstChild = (uint16_t)fNodesCount;
+ } else {
+ fNodes[prevIndex].fNextSibling = (uint16_t)fNodesCount;
+ }
+ ++fNodesCount;
+ return node;
+}
+
+CharacterNode*
+TextTrieMap::getChildNode(CharacterNode *parent, UChar c) const {
+ // Linear search of the sorted list of children.
+ uint16_t nodeIndex = parent->fFirstChild;
+ while (nodeIndex > 0) {
+ CharacterNode *current = fNodes + nodeIndex;
+ UChar childCharacter = current->fCharacter;
+ if (childCharacter == c) {
+ return current;
+ } else if (childCharacter > c) {
+ break;
+ }
+ nodeIndex = current->fNextSibling;
+ }
+ return NULL;
+}
+
+// Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
+static UMTX TextTrieMutex;
+
+// buildTrie() - The Trie node structure is needed. Create it from the data that was
+// saved at the time the ZoneStringFormatter was created. The Trie is only
+// needed for parsing operations, which are less common than formatting,
+// and the Trie is big, which is why its creation is deferred until first use.
+void TextTrieMap::buildTrie(UErrorCode &status) {
+ umtx_lock(&TextTrieMutex);
+ if (fLazyContents != NULL) {
+ for (int32_t i=0; i<fLazyContents->size(); i+=2) {
+ const UChar *key = (UChar *)fLazyContents->elementAt(i);
+ void *val = fLazyContents->elementAt(i+1);
+ UnicodeString keyString(TRUE, key, -1); // Aliasing UnicodeString constructor.
+ putImpl(keyString, val, status);
+ }
+ delete fLazyContents;
+ fLazyContents = NULL;
+ }
+ umtx_unlock(&TextTrieMutex);
+}
+
+void
+TextTrieMap::search(const UnicodeString &text, int32_t start,
+ TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
+ UBool trieNeedsInitialization = FALSE;
+ UMTX_CHECK(&TextTrieMutex, fLazyContents != NULL, trieNeedsInitialization);
+ if (trieNeedsInitialization) {
+ TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
+ nonConstThis->buildTrie(status);
+ }
+ if (fNodes == NULL) {
+ return;
+ }
+ search(fNodes, 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;
+ }
+ if (node->hasValues()) {
+ if (!handler->handleMatch(index - start, node, 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 = getChildNode(node, c);
+ if (node == NULL) {
+ break;
+ }
+ tmpidx = tmp.moveIndex32(tmpidx, 1);
+ }
+ } else {
+ node = getChildNode(node, c);
+ }
+ if (node != NULL) {
+ search(node, text, start, index+1, handler, status);
+ }
+}
+
+// ---------------------------------------------------
+// ZNStringPool class implementation
+// ---------------------------------------------------
+static const int32_t POOL_CHUNK_SIZE = 2000;
+struct ZNStringPoolChunk: public UMemory {
+ ZNStringPoolChunk *fNext; // Ptr to next pool chunk
+ int32_t fLimit; // Index to start of unused area at end of fStrings
+ UChar fStrings[POOL_CHUNK_SIZE]; // Strings array
+ ZNStringPoolChunk();
+};
+
+ZNStringPoolChunk::ZNStringPoolChunk() {
+ fNext = NULL;
+ fLimit = 0;
+}
+
+ZNStringPool::ZNStringPool(UErrorCode &status) {
+ fChunks = NULL;
+ fHash = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fChunks = new ZNStringPoolChunk;
+ if (fChunks == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ fHash = uhash_open(uhash_hashUChars /* keyHash */,
+ uhash_compareUChars /* keyComp */,
+ uhash_compareUChars /* valueComp */,
+ &status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+}
+
+ZNStringPool::~ZNStringPool() {
+ if (fHash != NULL) {
+ uhash_close(fHash);
+ fHash = NULL;
+ }
+
+ while (fChunks != NULL) {
+ ZNStringPoolChunk *nextChunk = fChunks->fNext;
+ delete fChunks;
+ fChunks = nextChunk;
+ }
+}
+
+static const UChar EmptyString = 0;
+
+const UChar *ZNStringPool::get(const UChar *s, UErrorCode &status) {
+ const UChar *pooledString;
+ if (U_FAILURE(status)) {
+ return &EmptyString;
+ }
+
+ pooledString = static_cast<UChar *>(uhash_get(fHash, s));
+ if (pooledString != NULL) {
+ return pooledString;
+ }
+
+ int32_t length = u_strlen(s);
+ int32_t remainingLength = POOL_CHUNK_SIZE - fChunks->fLimit;
+ if (remainingLength <= length) {
+ U_ASSERT(length < POOL_CHUNK_SIZE);
+ if (length >= POOL_CHUNK_SIZE) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return &EmptyString;
+ }
+ ZNStringPoolChunk *oldChunk = fChunks;
+ fChunks = new ZNStringPoolChunk;
+ if (fChunks == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return &EmptyString;
+ }
+ fChunks->fNext = oldChunk;
+ }
+
+ UChar *destString = &fChunks->fStrings[fChunks->fLimit];
+ u_strcpy(destString, s);
+ fChunks->fLimit += (length + 1);
+ uhash_put(fHash, destString, destString, &status);
+ return destString;
+}
+
+
+//
+// ZNStringPool::adopt() Put a string into the hash, but do not copy the string data
+// into the pool's storage. Used for strings from resource bundles,
+// which will perisist for the life of the zone string formatter, and
+// therefore can be used directly without copying.
+const UChar *ZNStringPool::adopt(const UChar * s, UErrorCode &status) {
+ const UChar *pooledString;
+ if (U_FAILURE(status)) {
+ return &EmptyString;
+ }
+ if (s != NULL) {
+ pooledString = static_cast<UChar *>(uhash_get(fHash, s));
+ if (pooledString == NULL) {
+ UChar *ncs = const_cast<UChar *>(s);
+ uhash_put(fHash, ncs, ncs, &status);
+ }
+ }
+ return s;
+}
+
+
+const UChar *ZNStringPool::get(const UnicodeString &s, UErrorCode &status) {
+ UnicodeString &nonConstStr = const_cast<UnicodeString &>(s);
+ return this->get(nonConstStr.getTerminatedBuffer(), status);
+}
+
+/*
+ * freeze(). Close the hash table that maps to the pooled strings.
+ * After freezing, the pool can not be searched or added to,
+ * but all existing references to pooled strings remain valid.
+ *
+ * The main purpose is to recover the storage used for the hash.
+ */
+void ZNStringPool::freeze() {
+ uhash_close(fHash);
+ fHash = NULL;
+}
+
+
+// ---------------------------------------------------
+// ZNames - names common for time zone and meta zone
+// ---------------------------------------------------
+class ZNames : public UMemory {
+public:
+ virtual ~ZNames();
+
+ static ZNames* createInstance(UResourceBundle* rb, const char* key);
+ const UChar* getName(UTimeZoneNameType type);
+
+protected:
+ ZNames(const UChar** names, UBool shortCommonlyUsed);
+ static const UChar** loadData(UResourceBundle* rb, const char* key, UBool& shortCommonlyUsed);
+
+private:
+ const UChar** fNames;
+ UBool fShortCommonlyUsed;
+};
+
+ZNames::ZNames(const UChar** names, UBool shortCommonlyUsed)
+: fNames(names), fShortCommonlyUsed(shortCommonlyUsed) {
+}
+
+ZNames::~ZNames() {
+ if (fNames != NULL) {
+ uprv_free(fNames);
+ }
+}
+
+ZNames*
+ZNames::createInstance(UResourceBundle* rb, const char* key) {
+ UBool shortCommonlyUsed = FALSE;
+ const UChar** names = loadData(rb, key, shortCommonlyUsed);
+ if (names == NULL) {
+ // No names data available
+ return NULL;
+ }
+ return new ZNames(names, shortCommonlyUsed);
+}
+
+const UChar*
+ZNames::getName(UTimeZoneNameType type) {
+ if (fNames == NULL) {
+ return NULL;
+ }
+ const UChar *name = NULL;
+ switch(type) {
+ case UTZNM_LONG_GENERIC:
+ name = fNames[0];
+ break;
+ case UTZNM_LONG_STANDARD:
+ name = fNames[1];
+ break;
+ case UTZNM_LONG_DAYLIGHT:
+ name = fNames[2];
+ break;
+ case UTZNM_SHORT_GENERIC:
+ if (fShortCommonlyUsed) {
+ name = fNames[3];
+ }
+ break;
+ case UTZNM_SHORT_STANDARD:
+ name = fNames[4];
+ break;
+ case UTZNM_SHORT_DAYLIGHT:
+ name = fNames[5];
+ break;
+ case UTZNM_SHORT_STANDARD_COMMONLY_USED:
+ if (fShortCommonlyUsed) {
+ name = fNames[4];
+ }
+ break;
+ case UTZNM_SHORT_DAYLIGHT_COMMONLY_USED:
+ if (fShortCommonlyUsed) {
+ name = fNames[5];
+ }
+ break;
+ default:
+ name = NULL;
+ }
+ return name;
+}
+
+const UChar**
+ZNames::loadData(UResourceBundle* rb, const char* key, UBool& shortCommonlyUsed) {
+ if (rb == NULL || key == NULL || *key == 0) {
+ return NULL;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ const UChar **names = NULL;
+
+ UResourceBundle* rbTable = NULL;
+ rbTable = ures_getByKeyWithFallback(rb, key, rbTable, &status);
+ if (U_SUCCESS(status)) {
+ names = (const UChar **)uprv_malloc(sizeof(const UChar*) * KEYS_SIZE);
+ if (names != NULL) {
+ UBool isEmpty = TRUE;
+ for (int32_t i = 0; i < KEYS_SIZE; i++) {
+ status = U_ZERO_ERROR;
+ int32_t len = 0;
+ const UChar *value = ures_getStringByKeyWithFallback(rbTable, KEYS[i], &len, &status);
+ if (U_FAILURE(status) || len == 0) {
+ names[i] = NULL;
+ } else {
+ names[i] = value;
+ isEmpty = FALSE;
+ }
+ }
+ if (isEmpty) {
+ // No need to keep the names array
+ uprv_free(names);
+ names = NULL;
+ }
+ }
+
+ if (names != NULL) {
+ status = U_ZERO_ERROR;
+ UResourceBundle* cuRes = ures_getByKeyWithFallback(rbTable, gCuTag, NULL, &status);
+ int32_t cu = ures_getInt(cuRes, &status);
+ if (U_SUCCESS(status)) {
+ shortCommonlyUsed = (cu != 0);
+ }
+ ures_close(cuRes);
+ }
+ }
+ ures_close(rbTable);
+ return names;
+}
+
+// ---------------------------------------------------
+// TZNames - names for a time zone
+// ---------------------------------------------------
+class TZNames : public ZNames {
+public:
+ virtual ~TZNames();
+
+ static TZNames* createInstance(UResourceBundle* rb, const char* key);
+ const UChar* getLocationName(void);
+
+private:
+ TZNames(const UChar** names, UBool shortCommonlyUsed, const UChar* locationName);
+ const UChar* fLocationName;
+};
+
+TZNames::TZNames(const UChar** names, UBool shortCommonlyUsed, const UChar* locationName)
+: ZNames(names, shortCommonlyUsed), fLocationName(locationName) {
+}
+
+TZNames::~TZNames() {
+}
+
+const UChar*
+TZNames::getLocationName() {
+ return fLocationName;
+}
+
+TZNames*
+TZNames::createInstance(UResourceBundle* rb, const char* key) {
+ if (rb == NULL || key == NULL || *key == 0) {
+ return NULL;
+ }
+ TZNames* tznames = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle* rbTable = ures_getByKeyWithFallback(rb, key, NULL, &status);
+ if (U_SUCCESS(status)) {
+ int32_t len = 0;
+ const UChar* locationName = ures_getStringByKeyWithFallback(rbTable, gEcTag, &len, &status);
+ if (U_FAILURE(status) || len == 0) {
+ locationName = NULL;
+ }
+
+ UBool shortCommonlyUsed = FALSE;
+ const UChar** names = loadData(rb, key, shortCommonlyUsed);
+
+ if (locationName != NULL || names != NULL) {
+ tznames = new TZNames(names, shortCommonlyUsed, locationName);
+ }
+ }
+ ures_close(rbTable);
+ return tznames;
+}
+
+// ---------------------------------------------------
+// The meta zone ID enumeration class
+// ---------------------------------------------------
+class MetaZoneIDsEnumeration : public StringEnumeration {
+public:
+ MetaZoneIDsEnumeration();
+ MetaZoneIDsEnumeration(const UVector& mzIDs);
+ MetaZoneIDsEnumeration(UVector* mzIDs);
+ virtual ~MetaZoneIDsEnumeration();
+ 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 fLen;
+ int32_t fPos;
+ const UVector* fMetaZoneIDs;
+ UVector *fLocalVector;
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MetaZoneIDsEnumeration)
+
+MetaZoneIDsEnumeration::MetaZoneIDsEnumeration()
+: fLen(0), fPos(0), fMetaZoneIDs(NULL), fLocalVector(NULL) {
+}
+
+MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(const UVector& mzIDs)
+: fPos(0), fMetaZoneIDs(&mzIDs), fLocalVector(NULL) {
+ fLen = fMetaZoneIDs->size();
+}
+
+MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(UVector *mzIDs)
+: fLen(0), fPos(0), fMetaZoneIDs(mzIDs), fLocalVector(mzIDs) {
+ if (fMetaZoneIDs) {
+ fLen = fMetaZoneIDs->size();
+ }
+}
+
+const UnicodeString*
+MetaZoneIDsEnumeration::snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && fMetaZoneIDs != NULL && fPos < fLen) {
+ unistr.setTo((const UChar*)fMetaZoneIDs->elementAt(fPos++), -1);
+ return &unistr;
+ }
+ return NULL;
+}
+
+void
+MetaZoneIDsEnumeration::reset(UErrorCode& /*status*/) {
+ fPos = 0;
+}
+
+int32_t
+MetaZoneIDsEnumeration::count(UErrorCode& /*status*/) const {
+ return fLen;
+}
+
+MetaZoneIDsEnumeration::~MetaZoneIDsEnumeration() {
+ if (fLocalVector) {
+ delete fLocalVector;
+ }
+}
+
+U_CDECL_BEGIN
+/**
+ * ZNameInfo stores zone name information in the trie
+ */
+typedef struct ZNameInfo {
+ UTimeZoneNameType type;
+ const UChar* tzID;
+ const UChar* mzID;
+} ZNameInfo;
+
+/**
+ * ZMatchInfo stores zone name match information used by find method
+ */
+typedef struct ZMatchInfo {
+ const ZNameInfo* znameInfo;
+ int32_t matchLength;
+} ZMatchInfo;
+U_CDECL_END
+
+// ---------------------------------------------------
+// The class stores time zone name match information
+// ---------------------------------------------------
+class TimeZoneNameMatchInfoImpl : public TimeZoneNameMatchInfo {
+public:
+ TimeZoneNameMatchInfoImpl(UVector* matches);
+ ~TimeZoneNameMatchInfoImpl();
+
+ int32_t size() const;
+ UTimeZoneNameType getNameType(int32_t index) const;
+ int32_t getMatchLength(int32_t index) const;
+ UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
+ UnicodeString& getMetaZoneID(int32_t index, UnicodeString& mzID) const;
+
+private:
+ UVector* fMatches; // vector of MatchEntry
+};
+
+TimeZoneNameMatchInfoImpl::TimeZoneNameMatchInfoImpl(UVector* matches)
+: fMatches(matches) {
+}
+
+TimeZoneNameMatchInfoImpl::~TimeZoneNameMatchInfoImpl() {
+ if (fMatches != NULL) {
+ delete fMatches;
+ }
+}
+
+int32_t
+TimeZoneNameMatchInfoImpl::size() const {
+ if (fMatches == NULL) {
+ return 0;
+ }
+ return fMatches->size();
+}
+
+UTimeZoneNameType
+TimeZoneNameMatchInfoImpl::getNameType(int32_t index) const {
+ ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL) {
+ return minfo->znameInfo->type;
+ }
+ return UTZNM_UNKNOWN;
+}
+
+int32_t
+TimeZoneNameMatchInfoImpl::getMatchLength(int32_t index) const {
+ ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL) {
+ return minfo->matchLength;
+ }
+ return -1;
+}
+
+UnicodeString&
+TimeZoneNameMatchInfoImpl::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
+ ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL && minfo->znameInfo->tzID != NULL) {
+ tzID.setTo(TRUE, minfo->znameInfo->tzID, -1);
+ } else {
+ tzID.setToBogus();
+ }
+ return tzID;
+}
+
+UnicodeString&
+TimeZoneNameMatchInfoImpl::getMetaZoneID(int32_t index, UnicodeString& mzID) const {
+ ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
+ if (minfo != NULL && minfo->znameInfo->mzID != NULL) {
+ mzID.setTo(TRUE, minfo->znameInfo->mzID, -1);
+ } else {
+ mzID.setToBogus();
+ }
+ return mzID;
+}
+
+// ---------------------------------------------------
+// ZNameSearchHandler
+// ---------------------------------------------------
+class ZNameSearchHandler : public TextTrieMapSearchResultHandler {
+public:
+ ZNameSearchHandler(uint32_t types);
+ virtual ~ZNameSearchHandler();
+
+ UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
+ UVector* getMatches(int32_t& maxMatchLen);
+
+private:
+ uint32_t fTypes;
+ UVector* fResults;
+ int32_t fMaxMatchLen;
+};
+
+ZNameSearchHandler::ZNameSearchHandler(uint32_t types)
+: fTypes(types), fResults(NULL), fMaxMatchLen(0) {
+}
+
+ZNameSearchHandler::~ZNameSearchHandler() {
+ if (fResults != NULL) {
+ delete fResults;
+ }
+}
+
+UBool
+ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (node->hasValues()) {
+ int32_t valuesCount = node->countValues();
+ for (int32_t i = 0; i < valuesCount; i++) {
+ ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
+ if (nameinfo == NULL) {
+ break;
+ }
+ if ((nameinfo->type & fTypes) != 0) {
+ // matches a requested type
+ if (fResults == NULL) {
+ fResults = new UVector(uprv_free, NULL, status);
+ if (fResults == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ if (U_SUCCESS(status)) {
+ ZMatchInfo *zmatch = (ZMatchInfo *)uprv_malloc(sizeof(ZMatchInfo));
+ if (zmatch == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ // add the match to the vector
+ zmatch->znameInfo = nameinfo;
+ zmatch->matchLength = matchLength;
+ fResults->addElement(zmatch, status);
+ if (U_FAILURE(status)) {
+ uprv_free(zmatch);
+ } else {
+ if (matchLength > fMaxMatchLen) {
+ fMaxMatchLen = matchLength;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+UVector*
+ZNameSearchHandler::getMatches(int32_t& maxMatchLen) {
+ // give the ownership to the caller
+ UVector *results = fResults;
+ maxMatchLen = fMaxMatchLen;
+
+ // reset
+ fResults = NULL;
+ fMaxMatchLen = 0;
+ return results;
+}
+
+// ---------------------------------------------------
+// TimeZoneNamesImpl
+//
+// TimeZoneNames implementation class. This is the main
+// part of this module.
+// ---------------------------------------------------
+
+U_CDECL_BEGIN
+/**
+ * Deleter for ZNames
+ */
+static void U_CALLCONV
+deleteZNames(void *obj) {
+ if (obj != EMPTY) {
+ delete (ZNames *)obj;
+ }
+}
+/**
+ * Deleter for TZNames
+ */
+static void U_CALLCONV
+deleteTZNames(void *obj) {
+ if (obj != EMPTY) {
+ delete (TZNames *)obj;
+ }
+}
+
+/**
+ * Deleter for ZNameInfo
+ */
+static void U_CALLCONV
+deleteZNameInfo(void *obj) {
+ uprv_free(obj);
+}
+
+U_CDECL_END
+
+TimeZoneNamesImpl::TimeZoneNamesImpl(const Locale& locale, UErrorCode& status)
+: fLocale(locale),
+ fLock(NULL),
+ fZoneStrings(NULL),
+ fTZNamesMap(NULL),
+ fMZNamesMap(NULL),
+ fNamesTrieFullyLoaded(FALSE),
+ fNamesTrie(TRUE, deleteZNameInfo) {
+ initialize(locale, status);
+}
+
+void
+TimeZoneNamesImpl::initialize(const Locale& locale, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Load zoneStrings bundle
+ UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning..
+ fZoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
+ fZoneStrings = ures_getByKeyWithFallback(fZoneStrings, gZoneStrings, fZoneStrings, &tmpsts);
+ if (U_FAILURE(tmpsts)) {
+ status = tmpsts;
+ cleanup();
+ return;
+ }
+
+ // Initialize hashtables holding time zone/meta zone names
+ fMZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ fTZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ cleanup();
+ return;
+ }
+
+ uhash_setValueDeleter(fMZNamesMap, deleteZNames);
+ uhash_setValueDeleter(fTZNamesMap, deleteTZNames);
+ // no key deleters for name maps
+
+ // preload zone strings for the default zone
+ TimeZone *tz = TimeZone::createDefault();
+ const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
+ if (tzID != NULL) {
+ loadStrings(UnicodeString(tzID));
+ }
+ delete tz;
+
+ return;
+}
+
+/*
+ * This method updates the cache and must be called with a lock,
+ * except initializer.
+ */
+void
+TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID) {
+ loadTimeZoneNames(tzCanonicalID);
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringEnumeration *mzIDs = getAvailableMetaZoneIDs(tzCanonicalID, status);
+ if (U_SUCCESS(status) && mzIDs != NULL) {
+ const UnicodeString *mzID;
+ while ((mzID = mzIDs->snext(status))) {
+ if (U_FAILURE(status)) {
+ break;
+ }
+ loadMetaZoneNames(*mzID);
+ }
+ delete mzIDs;
+ }
+}
+
+TimeZoneNamesImpl::~TimeZoneNamesImpl() {
+ cleanup();
+ umtx_destroy(&fLock);
+}
+
+void
+TimeZoneNamesImpl::cleanup() {
+ if (fZoneStrings != NULL) {
+ ures_close(fZoneStrings);
+ fZoneStrings = NULL;
+ }
+ if (fMZNamesMap != NULL) {
+ uhash_close(fMZNamesMap);
+ fMZNamesMap = NULL;
+ }
+ if (fTZNamesMap != NULL) {
+ uhash_close(fTZNamesMap);
+ fTZNamesMap = NULL;
+ }
+}
+
+StringEnumeration*
+TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ const UVector* mzIDs = ZoneMeta::getAvailableMetazoneIDs();
+ if (mzIDs == NULL) {
+ return new MetaZoneIDsEnumeration();
+ }
+ return new MetaZoneIDsEnumeration(*mzIDs);
+}
+
+StringEnumeration*
+TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ const UVector* mappings = ZoneMeta::getMetazoneMappings(tzID);
+ if (mappings == NULL) {
+ return new MetaZoneIDsEnumeration();
+ }
+
+ MetaZoneIDsEnumeration *senum = NULL;
+ UVector* mzIDs = new UVector(NULL, uhash_compareUChars, status);
+ if (mzIDs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_SUCCESS(status)) {
+ for (int32_t i = 0; U_SUCCESS(status) && i < mappings->size(); i++) {
+
+ OlsonToMetaMappingEntry *map = (OlsonToMetaMappingEntry *)mappings->elementAt(i);
+ const UChar *mzID = map->mzid;
+ if (!mzIDs->contains((void *)mzID)) {
+ mzIDs->addElement((void *)mzID, status);
+ }
+ }
+ if (U_SUCCESS(status)) {
+ senum = new MetaZoneIDsEnumeration(mzIDs);
+ } else {
+ delete mzIDs;
+ }
+ }
+ return senum;
+}
+
+UnicodeString&
+TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
+ ZoneMeta::getMetazoneID(tzID, date, mzID);
+ return mzID;
+}
+
+UnicodeString&
+TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
+ ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID);
+ return tzID;
+}
+
+UnicodeString&
+TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID,
+ UTimeZoneNameType type,
+ UnicodeString& name) const {
+ name.setToBogus(); // cleanup result.
+ if (mzID.isEmpty()) {
+ return name;
+ }
+
+ ZNames *znames = NULL;
+ TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ znames = nonConstThis->loadMetaZoneNames(mzID);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (znames != NULL) {
+ const UChar* s = znames->getName(type);
+ if (s != NULL) {
+ name.setTo(TRUE, s, -1);
+ }
+ }
+ return name;
+}
+
+UnicodeString&
+TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
+ name.setToBogus(); // cleanup result.
+ if (tzID.isEmpty()) {
+ return name;
+ }
+
+ TZNames *tznames = NULL;
+ TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ tznames = nonConstThis->loadTimeZoneNames(tzID);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (tznames != NULL) {
+ const UChar *s = tznames->getName(type);
+ if (s != NULL) {
+ name.setTo(TRUE, s, -1);
+ }
+ }
+ return name;
+}
+
+UnicodeString&
+TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
+ const UChar* locName = NULL;
+ TZNames *tznames = NULL;
+ TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ tznames = nonConstThis->loadTimeZoneNames(tzID);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (tznames != NULL) {
+ locName = tznames->getLocationName();
+ }
+ if (locName != NULL) {
+ name.setTo(TRUE, locName, -1);
+ return name;
+ }
+
+ return TimeZoneNames::getExemplarLocationName(tzID, name);
+}
+
+
+// Merge the MZ_PREFIX and mzId
+static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) {
+ if (mzID.isEmpty()) {
+ result[0] = '\0';
+ return;
+ }
+
+ char mzIdChar[ZID_KEY_MAX + 1];
+ int32_t keyLen;
+ int32_t prefixLen = uprv_strlen(gMZPrefix);
+ keyLen = mzID.extract(0, mzID.length(), mzIdChar, ZID_KEY_MAX + 1, US_INV);
+ uprv_memcpy((void *)result, (void *)gMZPrefix, prefixLen);
+ uprv_memcpy((void *)(result + prefixLen), (void *)mzIdChar, keyLen);
+ result[keyLen + prefixLen] = '\0';
+}
+
+/*
+ * This method updates the cache and must be called with a lock
+ */
+ZNames*
+TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID) {
+ if (mzID.length() > (ZID_KEY_MAX - MZ_PREFIX_LEN)) {
+ return NULL;
+ }
+
+ ZNames *znames = NULL;
+
+ UErrorCode status = U_ZERO_ERROR;
+ UChar mzIDKey[ZID_KEY_MAX + 1];
+ mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status);
+ U_ASSERT(status == U_ZERO_ERROR); // already checked length above
+ mzIDKey[mzID.length()] = 0;
+
+ void *cacheVal = uhash_get(fMZNamesMap, mzIDKey);
+ if (cacheVal == NULL) {
+ char key[ZID_KEY_MAX + 1];
+ mergeTimeZoneKey(mzID, key);
+ znames = ZNames::createInstance(fZoneStrings, key);
+
+ if (znames == NULL) {
+ cacheVal = (void *)EMPTY;
+ } else {
+ cacheVal = znames;
+ }
+ // Use the persistent ID as the resource key, so we can
+ // avoid duplications.
+ const UChar* newKey = ZoneMeta::findMetaZoneID(mzID);
+ if (newKey != NULL) {
+ uhash_put(fMZNamesMap, (void *)newKey, cacheVal, &status);
+ if (U_FAILURE(status)) {
+ if (znames != NULL) {
+ delete znames;
+ }
+ } else if (znames != NULL) {
+ // put the name info into the trie
+ for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) {
+ const UChar* name = znames->getName(ALL_NAME_TYPES[i]);
+ if (name != NULL) {
+ ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZNameInfo));
+ if (nameinfo != NULL) {
+ nameinfo->type = ALL_NAME_TYPES[i];
+ nameinfo->tzID = NULL;
+ nameinfo->mzID = newKey;
+ fNamesTrie.put(name, nameinfo, status);
+ }
+ }
+ }
+ }
+
+ } else {
+ // Should never happen with a valid input
+ if (znames != NULL) {
+ // It's not possible that we get a valid ZNames with unknown ID.
+ // But just in case..
+ delete znames;
+ znames = NULL;
+ }
+ }
+ } else if (cacheVal != EMPTY) {
+ znames = (ZNames *)cacheVal;
+ }
+
+ return znames;
+}
+
+/*
+ * This method updates the cache and must be called with a lock
+ */
+TZNames*
+TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID) {
+ if (tzID.length() > ZID_KEY_MAX) {
+ return NULL;
+ }
+
+ TZNames *tznames = NULL;
+
+ UErrorCode status = U_ZERO_ERROR;
+ UChar tzIDKey[ZID_KEY_MAX + 1];
+ int32_t tzIDKeyLen = tzID.extract(tzIDKey, ZID_KEY_MAX + 1, status);
+ U_ASSERT(status == U_ZERO_ERROR); // already checked length above
+ tzIDKey[tzIDKeyLen] = 0;
+
+ void *cacheVal = uhash_get(fTZNamesMap, tzIDKey);
+ if (cacheVal == NULL) {
+ char key[ZID_KEY_MAX + 1];
+ UErrorCode status = U_ZERO_ERROR;
+ // Replace "/" with ":".
+ UnicodeString uKey(tzID);
+ for (int32_t i = 0; i < uKey.length(); i++) {
+ if (uKey.charAt(i) == (UChar)0x2F) {
+ uKey.setCharAt(i, (UChar)0x3A);
+ }
+ }
+ uKey.extract(0, uKey.length(), key, sizeof(key), US_INV);
+ tznames = TZNames::createInstance(fZoneStrings, key);
+
+ if (tznames == NULL) {
+ cacheVal = (void *)EMPTY;
+ } else {
+ cacheVal = tznames;
+ }
+ // Use the persistent ID as the resource key, so we can
+ // avoid duplications.
+ const UChar* newKey = ZoneMeta::findTimeZoneID(tzID);
+ if (newKey != NULL) {
+ uhash_put(fTZNamesMap, (void *)newKey, cacheVal, &status);
+ if (U_FAILURE(status)) {
+ if (tznames != NULL) {
+ delete tznames;
+ }
+ } else if (tznames != NULL) {
+ // put the name info into the trie
+ for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) {
+ const UChar* name = tznames->getName(ALL_NAME_TYPES[i]);
+ if (name != NULL) {
+ ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZNameInfo));
+ if (nameinfo != NULL) {
+ nameinfo->type = ALL_NAME_TYPES[i];
+ nameinfo->tzID = newKey;
+ nameinfo->mzID = NULL;
+ fNamesTrie.put(name, nameinfo, status);
+ }
+ }
+ }
+ }
+ } else {
+ // Should never happen with a valid input
+ if (tznames != NULL) {
+ // It's not possible that we get a valid TZNames with unknown ID.
+ // But just in case..
+ delete tznames;
+ tznames = NULL;
+ }
+ }
+ } else if (cacheVal != EMPTY) {
+ tznames = (TZNames *)cacheVal;
+ }
+
+ return tznames;
+}
+
+TimeZoneNameMatchInfo*
+TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
+ ZNameSearchHandler handler(types);
+
+ TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ TimeZoneNameMatchInfoImpl *matchInfo = NULL;
+
+ int32_t maxLen = 0;
+ UVector *results = handler.getMatches(maxLen);
+ if (results != NULL && ((maxLen == (text.length() - start)) || fNamesTrieFullyLoaded)) {
+ // perfect match
+ matchInfo = new TimeZoneNameMatchInfoImpl(results);
+ if (matchInfo == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete results;
+ return NULL;
+ }
+ return matchInfo;
+ }
+
+ if (results != NULL) {
+ delete results;
+ }
+
+ // All names are not yet loaded into the trie
+ umtx_lock(&nonConstThis->fLock);
+ {
+ if (!fNamesTrieFullyLoaded) {
+ const UnicodeString *id;
+
+ // load strings for all zones
+ StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ while ((id = tzIDs->snext(status))) {
+ if (U_FAILURE(status)) {
+ break;
+ }
+ // loadStrings also load related metazone strings
+ nonConstThis->loadStrings(*id);
+ }
+ }
+ if (tzIDs != NULL) {
+ delete tzIDs;
+ }
+ if (U_SUCCESS(status)) {
+ nonConstThis->fNamesTrieFullyLoaded = TRUE;
+ }
+ }
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ umtx_lock(&nonConstThis->fLock);
+ {
+ // now try it again
+ fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
+ }
+ umtx_unlock(&nonConstThis->fLock);
+
+ results = handler.getMatches(maxLen);
+ if (results != NULL && maxLen > 0) {
+ matchInfo = new TimeZoneNameMatchInfoImpl(results);
+ if (matchInfo == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete results;
+ return NULL;
+ }
+ }
+
+ return matchInfo;
+}
+
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.h b/Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.h
new file mode 100644
index 00000000000..909a2926d58
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tznames_impl.h
@@ -0,0 +1,212 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2011, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TZNAMES_IMPL_H__
+#define __TZNAMES_IMPL_H__
+
+
+/**
+ * \file
+ * \brief C++ API: TimeZoneNames object
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tznames.h"
+#include "unicode/ures.h"
+#include "unicode/locid.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "umutex.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * ZNStringPool Pool of (UChar *) strings. Provides for sharing of repeated
+ * zone strings.
+ */
+struct ZNStringPoolChunk;
+class U_I18N_API ZNStringPool: public UMemory {
+ public:
+ ZNStringPool(UErrorCode &status);
+ ~ZNStringPool();
+
+ /* Get the pooled string that is equal to the supplied string s.
+ * Copy the string into the pool if it is not already present.
+ *
+ * Life time of the returned string is that of the pool.
+ */
+ const UChar *get(const UChar *s, UErrorCode &status);
+
+ /* Get the pooled string that is equal to the supplied string s.
+ * Copy the string into the pool if it is not already present.
+ */
+ const UChar *get(const UnicodeString &s, UErrorCode &status);
+
+ /* Adopt a string into the pool, without copying it.
+ * Used for strings from resource bundles, which will persist without copying.
+ */
+ const UChar *adopt(const UChar *s, UErrorCode &status);
+
+ /* Freeze the string pool. Discards the hash table that is used
+ * for looking up a string. All pointers to pooled strings remain valid.
+ */
+ void freeze();
+
+ private:
+ ZNStringPoolChunk *fChunks;
+ UHashtable *fHash;
+};
+
+/*
+ * Character node used by TextTrieMap
+ */
+struct CharacterNode {
+ // No constructor or destructor.
+ // We malloc and free an uninitalized array of CharacterNode objects
+ // and clear and delete them ourselves.
+
+ void clear();
+ void deleteValues(UObjectDeleter *valueDeleter);
+
+ void addValue(void *value, UObjectDeleter *valueDeleter, UErrorCode &status);
+ inline UBool hasValues() const;
+ inline int32_t countValues() const;
+ inline const void *getValue(int32_t index) const;
+
+ void *fValues; // Union of one single value vs. UVector of values.
+ UChar fCharacter; // UTF-16 code unit.
+ uint16_t fFirstChild; // 0 if no children.
+ uint16_t fNextSibling; // 0 terminates the list.
+ UBool fHasValuesVector;
+ UBool fPadding;
+
+ // No value: fValues == NULL and fHasValuesVector == FALSE
+ // One value: fValues == value and fHasValuesVector == FALSE
+ // >=2 values: fValues == UVector of values and fHasValuesVector == TRUE
+};
+
+inline UBool CharacterNode::hasValues() const {
+ return (UBool)(fValues != NULL);
+}
+
+inline int32_t CharacterNode::countValues() const {
+ return
+ fValues == NULL ? 0 :
+ !fHasValuesVector ? 1 :
+ ((const UVector *)fValues)->size();
+}
+
+inline const void *CharacterNode::getValue(int32_t index) const {
+ if (!fHasValuesVector) {
+ return fValues; // Assume index == 0.
+ } else {
+ return ((const UVector *)fValues)->elementAt(index);
+ }
+}
+
+/*
+ * Search result handler callback interface used by TextTrieMap search.
+ */
+class TextTrieMapSearchResultHandler : public UMemory {
+public:
+ virtual UBool handleMatch(int32_t matchLength,
+ const CharacterNode *node, UErrorCode& status) = 0;
+ virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning
+};
+
+/**
+ * TextTrieMap is a trie implementation for supporting
+ * fast prefix match for the string key.
+ */
+class U_I18N_API TextTrieMap : public UMemory {
+public:
+ TextTrieMap(UBool ignoreCase, UObjectDeleter *valeDeleter);
+ virtual ~TextTrieMap();
+
+ void put(const UnicodeString &key, void *value, ZNStringPool &sp, UErrorCode &status);
+ void put(const UChar*, void *value, UErrorCode &status);
+ void search(const UnicodeString &text, int32_t start,
+ TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
+ int32_t isEmpty() const;
+
+private:
+ UBool fIgnoreCase;
+ CharacterNode *fNodes;
+ int32_t fNodesCapacity;
+ int32_t fNodesCount;
+
+ UVector *fLazyContents;
+ UBool fIsEmpty;
+ UObjectDeleter *fValueDeleter;
+
+ UBool growNodes();
+ CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status);
+ CharacterNode* getChildNode(CharacterNode *parent, UChar c) const;
+
+ void putImpl(const UnicodeString &key, void *value, UErrorCode &status);
+ void buildTrie(UErrorCode &status);
+ void search(CharacterNode *node, const UnicodeString &text, int32_t start,
+ int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
+};
+
+
+
+class ZNames;
+class TZNames;
+class TextTrieMap;
+
+class TimeZoneNamesImpl : public TimeZoneNames {
+public:
+ TimeZoneNamesImpl(const Locale& locale, UErrorCode& status);
+
+ virtual ~TimeZoneNamesImpl();
+
+ StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
+ StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
+
+ UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const;
+ UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const;
+
+ UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const;
+ UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const;
+
+ UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
+
+ TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
+
+private:
+
+ Locale fLocale;
+ UMTX fLock;
+
+ UResourceBundle* fZoneStrings;
+
+ UHashtable* fTZNamesMap;
+ UHashtable* fMZNamesMap;
+
+ UBool fNamesTrieFullyLoaded;
+ TextTrieMap fNamesTrie;
+
+ void initialize(const Locale& locale, UErrorCode& status);
+ void cleanup();
+
+ void loadStrings(const UnicodeString& tzCanonicalID);
+
+ ZNames* loadMetaZoneNames(const UnicodeString& mzId);
+ TZNames* loadTimeZoneNames(const UnicodeString& mzId);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TZNAMES_IMPL_H__
+//eof
+//
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/tzrule.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tzrule.cpp
new file mode 100644
index 00000000000..e54b9b875fc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tzrule.cpp
@@ -0,0 +1,627 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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) ||
+ (typeid(*this) == typeid(that) &&
+ 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) ||
+ (typeid(*this) == typeid(other) &&
+ 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) ||
+ (typeid(*this) == typeid(that) &&
+ 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 (typeid(*this) != typeid(other) || 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(UDate /*base*/,
+ int32_t /*prevRawOffset*/,
+ int32_t /*prevDSTSavings*/,
+ UBool /*inclusive*/,
+ UDate& /*result*/) const {
+ return FALSE;
+}
+
+UBool
+InitialTimeZoneRule::getPreviousStart(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 (typeid(*this) != typeid(that)) {
+ 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 (typeid(*this) != typeid(other) || 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(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(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 (typeid(*this) != typeid(that) || 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 (typeid(*this) != typeid(other) || 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(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(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-4.8.1/i18n/tztrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/tztrans.cpp
new file mode 100644
index 00000000000..f795e409288
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/tztrans.cpp
@@ -0,0 +1,146 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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 (typeid(*this) != typeid(that)) {
+ 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-4.8.1/i18n/ucal.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucal.cpp
new file mode 100644
index 00000000000..db1028cdfc7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucal.cpp
@@ -0,0 +1,705 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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 "cstring.h"
+#include "ustrenum.h"
+#include "uenumimp.h"
+#include "ulist.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_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
+ const int32_t* rawOffset, UErrorCode* ec) {
+ return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
+ zoneType, region, rawOffset, *ec), ec);
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ucal_openTimeZones(UErrorCode* ec) {
+ return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
+ return uenum_openFromStringEnumeration(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)) {
+ SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone);
+ if (stz != NULL) {
+ result = stz->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();
+}
+
+#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
+
+U_CAPI UCalendar* U_EXPORT2
+ucal_open( const UChar* zoneID,
+ int32_t len,
+ const char* locale,
+ UCalendarType caltype,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return 0;
+
+ TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
+ : _createTimeZone(zoneID, len, status);
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ if ( caltype == UCAL_GREGORIAN ) {
+ char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+ if ( locale == NULL ) {
+ locale = uloc_getDefault();
+ }
+ uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
+ uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status);
+ }
+ return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
+}
+
+U_CAPI void U_EXPORT2
+ucal_close(UCalendar *cal)
+{
+
+ delete (Calendar*) cal;
+}
+
+U_CAPI UCalendar* U_EXPORT2
+ucal_clone(const UCalendar* cal,
+ UErrorCode* status)
+{
+ if(U_FAILURE(*status)) return 0;
+
+ Calendar* res = ((Calendar*)cal)->clone();
+
+ if(res == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ return (UCalendar*) res;
+}
+
+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;
+ GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
+ // Not if(gregocal == NULL) {
+ // because we really want to work only with a GregorianCalendar, not with
+ // its subclasses like BuddhistCalendar.
+ if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
+ *pErrorCode = U_UNSUPPORTED_ERROR;
+ return;
+ }
+ gregocal->setGregorianChange(date, *pErrorCode);
+}
+
+U_CAPI UDate U_EXPORT2
+ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return (UDate)0;
+ }
+ const Calendar *cpp_cal = (const Calendar *)cal;
+ const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
+ // Not if(gregocal == NULL) {
+ // see comments in ucal_setGregorianChange().
+ if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
+ *pErrorCode = U_UNSUPPORTED_ERROR;
+ return (UDate)0;
+ }
+ return gregocal->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);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
+ UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
+ if(status == 0 || U_FAILURE(*status)) {
+ return 0;
+ }
+ if (isSystemID) {
+ *isSystemID = FALSE;
+ }
+ if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ int32_t reslen = 0;
+ UnicodeString canonical;
+ UBool systemID = FALSE;
+ TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
+ if (U_SUCCESS(*status)) {
+ if (isSystemID) {
+ *isSystemID = systemID;
+ }
+ reslen = canonical.extract(result, resultCapacity, *status);
+ }
+ return reslen;
+}
+
+U_CAPI const char * U_EXPORT2
+ucal_getType(const UCalendar *cal, UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ return ((Calendar*)cal)->getType();
+}
+
+U_CAPI UCalendarWeekdayType U_EXPORT2
+ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return UCAL_WEEKDAY;
+ }
+ return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
+}
+
+U_CAPI UBool U_EXPORT2
+ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ return ((Calendar*)cal)->isWeekend(date, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getFieldDifference(UCalendar* cal, UDate target,
+ UCalendarDateFields field,
+ UErrorCode* status )
+{
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ return ((Calendar*)cal)->fieldDifference(target, field, *status);
+}
+
+
+static const UEnumeration defaultKeywordValues = {
+ NULL,
+ NULL,
+ ulist_close_keyword_values_iterator,
+ ulist_count_keyword_values,
+ uenum_unextDefault,
+ ulist_next_keyword_value,
+ ulist_reset_keyword_values_iterator
+};
+
+static const char * const CAL_TYPES[] = {
+ "gregorian",
+ "japanese",
+ "buddhist",
+ "roc",
+ "persian",
+ "islamic-civil",
+ "islamic",
+ "hebrew",
+ "chinese",
+ "indian",
+ "coptic",
+ "ethiopic",
+ "ethiopic-amete-alem",
+ NULL
+};
+
+U_CAPI UEnumeration* U_EXPORT2
+ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
+ // Resolve region
+ char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
+ int32_t prefRegionLength = 0;
+ prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
+ if (prefRegionLength == 0) {
+ char loc[ULOC_FULLNAME_CAPACITY] = "";
+ int32_t locLength = 0;
+ locLength = uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
+
+ prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
+ }
+
+ // Read preferred calendar values from supplementalData calendarPreference
+ UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
+ ures_getByKey(rb, "calendarPreferenceData", rb, status);
+ UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
+ if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
+ *status = U_ZERO_ERROR;
+ order = ures_getByKey(rb, "001", NULL, status);
+ }
+
+ // Create a list of calendar type strings
+ UList *values = NULL;
+ if (U_SUCCESS(*status)) {
+ values = ulist_createEmptyList(status);
+ if (U_SUCCESS(*status)) {
+ for (int i = 0; i < ures_getSize(order); i++) {
+ int32_t len;
+ const UChar *type = ures_getStringByIndex(order, i, &len, status);
+ char *caltype = (char*)uprv_malloc(len + 1);
+ if (caltype == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ u_UCharsToChars(type, caltype, len);
+ *(caltype + len) = 0;
+
+ ulist_addItemEndList(values, caltype, TRUE, status);
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ }
+
+ if (U_SUCCESS(*status) && !commonlyUsed) {
+ // If not commonlyUsed, add other available values
+ for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
+ if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
+ ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ }
+ }
+ }
+ if (U_FAILURE(*status)) {
+ ulist_deleteList(values);
+ values = NULL;
+ }
+ }
+ }
+
+ ures_close(order);
+ ures_close(rb);
+
+ if (U_FAILURE(*status) || values == NULL) {
+ return NULL;
+ }
+
+ // Create string enumeration
+ UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
+ if (en == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ ulist_deleteList(values);
+ return NULL;
+ }
+ ulist_resetList(values);
+ memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
+ en->context = values;
+ return en;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.c b/Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.c
new file mode 100644
index 00000000000..cce5890d452
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.c
@@ -0,0 +1,60 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2009, 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"
+
+/** Auto-client for UCLN_I18N **/
+#define UCLN_TYPE UCLN_I18N
+#include "ucln_imp.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;
+ }
+ }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+ ucln_unRegisterAutomaticCleanup();
+#endif
+ 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;
+ }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+ ucln_registerAutomaticCleanup();
+#endif
+}
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.h
new file mode 100644
index 00000000000..ffe9247aace
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucln_in.h
@@ -0,0 +1,63 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2011, 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.
+It's usually best to have child dependencies called first. */
+typedef enum ECleanupI18NType {
+ UCLN_I18N_START = -1,
+ UCLN_I18N_TRANSLITERATOR,
+ UCLN_I18N_REGEX,
+ UCLN_I18N_ISLAMIC_CALENDAR,
+ UCLN_I18N_CHINESE_CALENDAR,
+ UCLN_I18N_HEBREW_CALENDAR,
+ UCLN_I18N_ASTRO_CALENDAR,
+ UCLN_I18N_CALENDAR,
+ UCLN_I18N_TIMEZONEFORMAT,
+ UCLN_I18N_TIMEZONENAMES,
+ UCLN_I18N_ZONEMETA,
+ UCLN_I18N_TIMEZONE,
+ UCLN_I18N_PLURAL_RULE,
+ UCLN_I18N_CURRENCY,
+ UCLN_I18N_DECFMT,
+ UCLN_I18N_NUMFMT,
+ UCLN_I18N_SMPDTFMT,
+ UCLN_I18N_USEARCH,
+ UCLN_I18N_COLLATOR,
+ UCLN_I18N_UCOL,
+ UCLN_I18N_UCOL_RES,
+ UCLN_I18N_UCOL_BLD,
+ UCLN_I18N_CSDET,
+ UCLN_I18N_COLL_DATA,
+ UCLN_I18N_INDEX_CHARACTERS,
+ 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 utrans_transliterator_cleanup(void);
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol.cpp
new file mode 100644
index 00000000000..162388cdf71
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol.cpp
@@ -0,0 +1,8237 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2011, 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"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/bytestream.h"
+#include "unicode/coleitr.h"
+#include "unicode/unorm.h"
+#include "unicode/udata.h"
+#include "unicode/ustring.h"
+
+#include "ucol_imp.h"
+#include "bocsu.h"
+
+#include "normalizer2impl.h"
+#include "unorm_it.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "ucln_in.h"
+#include "cstring.h"
+#include "utracimp.h"
+#include "putilimp.h"
+#include "uassert.h"
+
+#ifdef UCOL_DEBUG
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_USE
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+#define LAST_BYTE_MASK_ 0xFF
+#define SECOND_LAST_BYTE_SHIFT_ 8
+
+#define ZERO_CC_LIMIT_ 0xC0
+
+// 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;
+// Code points at fcdHighStart and above have a zero FCD value.
+static UChar32 fcdHighStart = 0;
+
+// 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 const int32_t maxRegularPrimary = 0x7A;
+static const int32_t minImplicitPrimary = 0xE0;
+static const int32_t maxImplicitPrimary = 0xE4;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+ucol_cleanup(void)
+{
+ fcdTrieIndex = NULL;
+ return TRUE;
+}
+
+static int32_t U_CALLCONV
+_getFoldingOffset(uint32_t data) {
+ return (int32_t)(data&0xFFFFFF);
+}
+
+U_CDECL_END
+
+// init FCD data
+static inline
+UBool initializeFCD(UErrorCode *status) {
+ if (fcdTrieIndex != NULL) {
+ return TRUE;
+ } else {
+ // The result is constant, until the library is reloaded.
+ fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, status);
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL, ucol_cleanup);
+ return U_SUCCESS(*status);
+ }
+}
+
+static
+inline void IInit_collIterate(const UCollator *collator, const UChar *sourceString,
+ int32_t sourceLen, collIterate *s,
+ UErrorCode *status)
+{
+ (s)->string = (s)->pos = 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)->extendCEs = NULL;
+ (s)->extendCEsSize = 0;
+ (s)->CEpos = (s)->toReturn = (s)->CEs;
+ (s)->offsetBuffer = NULL;
+ (s)->offsetBufferSize = 0;
+ (s)->offsetReturn = (s)->offsetStore = NULL;
+ (s)->offsetRepeatCount = (s)->offsetRepeatValue = 0;
+ (s)->coll = (collator);
+ (s)->nfd = Normalizer2Factory::getNFDInstance(*status);
+ (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,
+ UErrorCode *status) {
+ /* Out-of-line version for use from other files. */
+ IInit_collIterate(collator, sourceString, sourceLen, s, status);
+}
+
+U_CAPI collIterate * U_EXPORT2
+uprv_new_collIterate(UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ collIterate *s = new collIterate;
+ if(s == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return s;
+}
+
+U_CAPI void U_EXPORT2
+uprv_delete_collIterate(collIterate *s) {
+ delete s;
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_collIterateAtEnd(collIterate *s) {
+ return s == NULL || s->pos == s->endp;
+}
+
+/**
+* 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.getBuffer();
+ backup->buffersize = data->writableBuffer.length();
+ 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.getBuffer() != 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.getTerminatedBuffer() +
+ (data->pos - backup->bufferaddress);
+ }
+ else {
+ /* backwards direction */
+ int32_t temp = backup->buffersize -
+ (int32_t)(data->pos - backup->bufferaddress);
+ data->pos = data->writableBuffer.getTerminatedBuffer() + (data->writableBuffer.length() - 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;
+ }
+}
+
+static UBool
+reallocCEs(collIterate *data, int32_t newCapacity) {
+ uint32_t *oldCEs = data->extendCEs;
+ if(oldCEs == NULL) {
+ oldCEs = data->CEs;
+ }
+ int32_t length = data->CEpos - oldCEs;
+ uint32_t *newCEs = (uint32_t *)uprv_malloc(newCapacity * 4);
+ if(newCEs == NULL) {
+ return FALSE;
+ }
+ uprv_memcpy(newCEs, oldCEs, length * 4);
+ uprv_free(data->extendCEs);
+ data->extendCEs = newCEs;
+ data->extendCEsSize = newCapacity;
+ data->CEpos = newCEs + length;
+ return TRUE;
+}
+
+static UBool
+increaseCEsCapacity(collIterate *data) {
+ int32_t oldCapacity;
+ if(data->extendCEs != NULL) {
+ oldCapacity = data->extendCEsSize;
+ } else {
+ oldCapacity = LENGTHOF(data->CEs);
+ }
+ return reallocCEs(data, 2 * oldCapacity);
+}
+
+static UBool
+ensureCEsCapacity(collIterate *data, int32_t minCapacity) {
+ int32_t oldCapacity;
+ if(data->extendCEs != NULL) {
+ oldCapacity = data->extendCEsSize;
+ } else {
+ oldCapacity = LENGTHOF(data->CEs);
+ }
+ if(minCapacity <= oldCapacity) {
+ return TRUE;
+ }
+ oldCapacity *= 2;
+ return reallocCEs(data, minCapacity > oldCapacity ? minCapacity : oldCapacity);
+}
+
+void collIterate::appendOffset(int32_t offset, UErrorCode &errorCode) {
+ if(U_FAILURE(errorCode)) {
+ return;
+ }
+ int32_t length = offsetStore == NULL ? 0 : (int32_t)(offsetStore - offsetBuffer);
+ if(length >= offsetBufferSize) {
+ int32_t newCapacity = 2 * offsetBufferSize + UCOL_EXPAND_CE_BUFFER_SIZE;
+ int32_t *newBuffer = reinterpret_cast<int32_t *>(uprv_malloc(newCapacity * 4));
+ if(newBuffer == NULL) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if(length > 0) {
+ uprv_memcpy(newBuffer, offsetBuffer, length * 4);
+ }
+ uprv_free(offsetBuffer);
+ offsetBuffer = newBuffer;
+ offsetStore = offsetBuffer + length;
+ offsetBufferSize = newCapacity;
+ }
+ *offsetStore++ = offset;
+}
+
+/*
+* 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) ||
+
+
+/****************************************************************************/
+/* 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(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->actualLocale = NULL;
+ result->validLocale = NULL;
+ result->requestedLocale = NULL;
+ result->rules = NULL;
+ result->rulesLength = 0;
+ result->freeRulesOnClose = FALSE;
+ result->ucaRules = 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 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 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;
+ int32_t defaultReorderCodesSize = 0;
+ int32_t reorderCodesSize = 0;
+ uint8_t *image;
+ UChar *rules;
+ int32_t* defaultReorderCodes;
+ int32_t* reorderCodes;
+ uint8_t* leadBytePermutationTable;
+ 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;
+ }
+ // no padding for alignment needed from here since the next two are 4 byte quantities
+ if (coll->defaultReorderCodes) {
+ defaultReorderCodesSize = coll->defaultReorderCodesLength * sizeof(int32_t);
+ bufferSizeNeeded += defaultReorderCodesSize;
+ }
+ if (coll->reorderCodes) {
+ reorderCodesSize = coll->reorderCodesLength * sizeof(int32_t);
+ bufferSizeNeeded += reorderCodesSize;
+ }
+ if (coll->leadBytePermutationTable) {
+ bufferSizeNeeded += 256 * sizeof(uint8_t);
+ }
+
+ 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);
+ // Null pointer check.
+ if (stackBufferChars == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ colAllocated = TRUE;
+ if (U_SUCCESS(*status)) {
+ *status = U_SAFECLONE_ALLOCATED_WARNING;
+ }
+ }
+ localCollator = (UCollator *)stackBufferChars;
+ rules = (UChar *)(stackBufferChars + sizeof(UCollator) + rulesPadding);
+ defaultReorderCodes = (int32_t*)((uint8_t*)rules + rulesSize);
+ reorderCodes = (int32_t*)((uint8_t*)defaultReorderCodes + defaultReorderCodesSize);
+ leadBytePermutationTable = (uint8_t*)reorderCodes + reorderCodesSize;
+
+ {
+ UErrorCode tempStatus = U_ZERO_ERROR;
+ imageSize = ucol_cloneBinary(coll, NULL, 0, &tempStatus);
+ }
+ if (coll->freeImageOnClose) {
+ image = (uint8_t *)uprv_malloc(imageSize);
+ // Null pointer check
+ if (image == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ 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;
+ }
+
+ // collator reordering
+ if (coll->defaultReorderCodes) {
+ localCollator->defaultReorderCodes =
+ (int32_t*) uprv_memcpy(defaultReorderCodes, coll->defaultReorderCodes, coll->defaultReorderCodesLength * sizeof(int32_t));
+ localCollator->defaultReorderCodesLength = coll->defaultReorderCodesLength;
+ localCollator->freeDefaultReorderCodesOnClose = FALSE;
+ }
+ if (coll->reorderCodes) {
+ localCollator->reorderCodes =
+ (int32_t*)uprv_memcpy(reorderCodes, coll->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
+ localCollator->reorderCodesLength = coll->reorderCodesLength;
+ localCollator->freeReorderCodesOnClose = FALSE;
+ }
+ if (coll->leadBytePermutationTable) {
+ localCollator->leadBytePermutationTable =
+ (uint8_t*) uprv_memcpy(leadBytePermutationTable, coll->leadBytePermutationTable, 256);
+ localCollator->freeLeadBytePermutationTableOnClose = FALSE;
+ }
+
+ int32_t i;
+ for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
+ ucol_setAttribute(localCollator, (UColAttribute)i, ucol_getAttribute(coll, (UColAttribute)i, status), status);
+ }
+ // zero copies of pointers
+ localCollator->actualLocale = NULL;
+ localCollator->validLocale = NULL;
+ localCollator->requestedLocale = NULL;
+ localCollator->ucaRules = coll->ucaRules; // There should only be one copy here.
+ 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->actualLocale != NULL) {
+ uprv_free(coll->actualLocale);
+ }
+ if(coll->requestedLocale != NULL) {
+ uprv_free(coll->requestedLocale);
+ }
+ 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);
+ }
+
+ if(coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ if(coll->defaultReorderCodes != NULL && coll->freeDefaultReorderCodesOnClose == TRUE) {
+ uprv_free(coll->defaultReorderCodes);
+ }
+ if(coll->reorderCodes != NULL && coll->freeReorderCodesOnClose == TRUE) {
+ uprv_free(coll->reorderCodes);
+ }
+
+ /* 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;
+ if(result->normalizationMode == UCOL_ON && !initializeFCD(status)) {
+ return;
+ }
+ 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->alternateHandlingisDefault = 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 (c < coll->minContrEndCP) {
+ return FALSE;
+ }
+
+ int32_t hash = c;
+ uint8_t htbyte;
+ if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) {
+ if (U16_IS_TRAIL(c)) {
+ return TRUE;
+ }
+ 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 = 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->rules = NULL;
+ result->rulesLength = 0;
+ result->freeRulesOnClose = FALSE;
+ result->defaultReorderCodes = NULL;
+ result->defaultReorderCodesLength = 0;
+ result->freeDefaultReorderCodesOnClose = FALSE;
+ result->reorderCodes = NULL;
+ result->reorderCodesLength = 0;
+ result->freeReorderCodesOnClose = FALSE;
+ result->leadBytePermutationTable = NULL;
+ result->freeLeadBytePermutationTableOnClose = FALSE;
+
+ /* 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;
+
+ /* Normally these will be set correctly later. This is the default if you use UCA or the default. */
+ result->ucaRules = NULL;
+ result->actualLocale = NULL;
+ result->validLocale = NULL;
+ result->requestedLocale = NULL;
+ result->hasRealData = FALSE; // real data lives in .dat file...
+ result->freeImageOnClose = FALSE;
+
+ /* set attributes */
+ ucol_setOptionsFromHeader(
+ result,
+ (UColOptionSet*)((uint8_t*)result->image+result->image->options),
+ status);
+ result->freeOptionsOnClose = 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 initImplicitConstants()
+ */
+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
+ // 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
+ // 9FCB;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+ CJK_BASE = 0x4E00,
+ CJK_LIMIT = 0x9FCB+1,
+ // Unified CJK ideographs in the compatibility ideographs block.
+ CJK_COMPAT_USED_BASE = 0xFA0E,
+ CJK_COMPAT_USED_LIMIT = 0xFA2F+1,
+ // 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+ // 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+ CJK_A_BASE = 0x3400,
+ CJK_A_LIMIT = 0x4DB5+1,
+ // 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
+ // 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
+ CJK_B_BASE = 0x20000,
+ CJK_B_LIMIT = 0x2A6D6+1,
+ // 2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
+ // 2B734;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;;
+ CJK_C_BASE = 0x2A700,
+ CJK_C_LIMIT = 0x2B734+1,
+ // 2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;;
+ // 2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;;
+ CJK_D_BASE = 0x2B740,
+ CJK_D_LIMIT = 0x2B81D+1;
+ // when adding to this list, look for all occurrences (in project)
+ // of CJK_C_BASE and CJK_C_LIMIT, etc. to check for code that needs changing!!!!
+
+static UChar32 swapCJK(UChar32 i) {
+ if (i < CJK_A_BASE) {
+ // non-CJK
+ } else if (i < CJK_A_LIMIT) {
+ // Extension A has lower code points than the original Unihan+compat
+ // but sorts higher.
+ return i - CJK_A_BASE
+ + (CJK_LIMIT - CJK_BASE)
+ + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE);
+ } else if (i < CJK_BASE) {
+ // non-CJK
+ } else if (i < CJK_LIMIT) {
+ return i - CJK_BASE;
+ } else if (i < CJK_COMPAT_USED_BASE) {
+ // non-CJK
+ } else if (i < CJK_COMPAT_USED_LIMIT) {
+ return i - CJK_COMPAT_USED_BASE
+ + (CJK_LIMIT - CJK_BASE);
+ } else if (i < CJK_B_BASE) {
+ // non-CJK
+ } else if (i < CJK_B_LIMIT) {
+ return i; // non-BMP-CJK
+ } else if (i < CJK_C_BASE) {
+ // non-CJK
+ } else if (i < CJK_C_LIMIT) {
+ return i; // non-BMP-CJK
+ } else if (i < CJK_D_BASE) {
+ // non-CJK
+ } else if (i < CJK_D_LIMIT) {
+ return i; // non-BMP-CJK
+ }
+ 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) {
+ //fprintf(stdout, "Incoming: %04x\n", 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));
+ //fprintf(stdout, "CJK swapped: %04x\n", 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;
+ UChar32 b2 = (implicit >> 8) & 0xFF;
+ UChar32 b1 = (implicit >> 16) & 0xFF;
+ UChar32 b0 = (implicit >> 24) & 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.
+ * Maintenance Note: this function may end up being called more than once, due
+ * to threading races during initialization. Make sure that
+ * none of the Constants is ever transiently assigned an
+ * incorrect value.
+ * @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)
+ || (minTrailIn < 0 || minTrailIn >= maxTrailIn || maxTrailIn > 0xFF)
+ || (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);
+ int32_t neededPerFinalByte = divideAndRoundUp(neededPerPrimaryByte, medialCount * medialCount);
+ int32_t gap4 = (maxTrail - minTrail - 1) / neededPerFinalByte;
+ if (gap4 < 1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ final4Multiplier = gap4 + 1;
+ final4Count = neededPerFinalByte;
+ max4Trail = minTrail + (final4Count - 1) * final4Multiplier;
+}
+
+ /**
+ * Supply parameters for generating implicit CEs
+ */
+U_CAPI void U_EXPORT2
+uprv_uca_initImplicitConstants(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);
+}
+
+
+/* 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;
+ const UChar *srcP = collationSource->pos - 1; /* Start of chars to normalize */
+ const UChar *endP = collationSource->fcdPosition; /* End of region to normalize+1 */
+
+ collationSource->nfd->normalize(UnicodeString(FALSE, srcP, (int32_t)(endP - srcP)),
+ collationSource->writableBuffer,
+ status);
+ if (U_FAILURE(status)) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "collIterNormalize(), NFD failed, status = %s\n", u_errorName(status));
+#endif
+ return;
+ }
+
+ collationSource->pos = collationSource->writableBuffer.getTerminatedBuffer();
+ 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) {
+ 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.
+ /* trie access */
+ fcd = unorm_nextFCD16(fcdTrieIndex, fcdHighStart, srcP, endP);
+ if (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;
+
+ /* trie access */
+ fcd = unorm_nextFCD16(fcdTrieIndex, fcdHighStart, srcP, endP);
+ 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->extendCEs ? collationSource->extendCEs : collationSource->CEs;
+ }
+ return order;
+ }
+
+ UChar ch = 0;
+ collationSource->offsetReturn = NULL;
+
+ do {
+ 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.getBuffer()+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) {
+ /* Codepoints \u3099-\u309C are both Hiragana and Katakana. Set the flag
+ * based on whether the previous codepoint was Hiragana or Katakana.
+ */
+ if(((ch>=0x3040 && ch<=0x3096) || (ch >= 0x309d && ch <= 0x309f)) ||
+ ((collationSource->flags & UCOL_WAS_HIRAGANA) && (ch >= 0x3099 && ch <= 0x309C))) {
+ 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
+ {
+ // Always use UCA for Han, Hangul
+ // (Han extension A is before main Han block)
+ // **** Han compatibility chars ?? ****
+ if ((collationSource->flags & UCOL_FORCE_HAN_IMPLICIT) != 0 &&
+ (ch >= UCOL_FIRST_HAN_A && ch <= UCOL_LAST_HANGUL)) {
+ if (ch > UCOL_LAST_HAN && ch < UCOL_FIRST_HANGUL) {
+ // between the two target ranges; do normal lookup
+ // **** this range is YI, Modifier tone letters, ****
+ // **** Latin-D, Syloti Nagari, Phagas-pa. ****
+ // **** Latin-D might be tailored, so we need to ****
+ // **** do the normal lookup for these guys. ****
+ order = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+ } else {
+ // in one of the target ranges; use UCA
+ order = UCOL_NOT_FOUND;
+ }
+ } 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);
+ }
+ }
+ }
+ } while ( order == UCOL_IGNORABLE && ch >= UCOL_FIRST_HANGUL && ch <= UCOL_LAST_HANGUL );
+
+ 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;
+ const UChar *pEnd = data->pos; /* End normalize + 1 */
+ const UChar *pStart;
+
+ /* Start normalize */
+ if (data->fcdPosition == NULL) {
+ pStart = data->string;
+ }
+ else {
+ pStart = data->fcdPosition + 1;
+ }
+
+ int32_t normLen =
+ data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)((pEnd - pStart) + 1)),
+ data->writableBuffer,
+ status).
+ length();
+ if(U_FAILURE(status)) {
+ return;
+ }
+ /*
+ this puts the null termination infront of the normalized string instead
+ of the end
+ */
+ data->writableBuffer.insert(0, (UChar)0);
+
+ /*
+ * The usual case at this point is that we've got a base
+ * character followed by marks that were normalized. If
+ * fcdPosition is NULL, that means that we backed up to
+ * the beginning of the string and there's no base character.
+ *
+ * Forward processing will usually normalize when it sees
+ * the first mark, so that mark will get it's natural offset
+ * and the rest will get the offset of the character following
+ * the marks. The base character will also get its natural offset.
+ *
+ * We write the offset of the base character, if there is one,
+ * followed by the offset of the first mark and then the offsets
+ * of the rest of the marks.
+ */
+ int32_t firstMarkOffset = 0;
+ int32_t trailOffset = (int32_t)(data->pos - data->string + 1);
+ int32_t trailCount = normLen - 1;
+
+ if (data->fcdPosition != NULL) {
+ int32_t baseOffset = (int32_t)(data->fcdPosition - data->string);
+ UChar baseChar = *data->fcdPosition;
+
+ firstMarkOffset = baseOffset + 1;
+
+ /*
+ * If the base character is the start of a contraction, forward processing
+ * will normalize the marks while checking for the contraction, which means
+ * that the offset of the first mark will the same as the other marks.
+ *
+ * **** THIS IS PROBABLY NOT A COMPLETE TEST ****
+ */
+ if (baseChar >= 0x100) {
+ uint32_t baseOrder = UTRIE_GET32_FROM_LEAD(&data->coll->mapping, baseChar);
+
+ if (baseOrder == UCOL_NOT_FOUND && data->coll->UCA) {
+ baseOrder = UTRIE_GET32_FROM_LEAD(&data->coll->UCA->mapping, baseChar);
+ }
+
+ if (baseOrder > UCOL_NOT_FOUND && getCETag(baseOrder) == CONTRACTION_TAG) {
+ firstMarkOffset = trailOffset;
+ }
+ }
+
+ data->appendOffset(baseOffset, status);
+ }
+
+ data->appendOffset(firstMarkOffset, status);
+
+ for (int32_t i = 0; i < trailCount; i += 1) {
+ data->appendOffset(trailOffset, status);
+ }
+
+ data->offsetRepeatValue = trailOffset;
+
+ data->offsetReturn = data->offsetStore - 1;
+ if (data->offsetReturn == data->offsetBuffer) {
+ data->offsetStore = data->offsetBuffer;
+ }
+
+ data->pos = data->writableBuffer.getTerminatedBuffer() + 1 + normLen;
+ 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;
+ 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. */
+ fcd = unorm_prevFCD16(fcdTrieIndex, fcdHighStart, start, src);
+
+ 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;
+ }
+
+ fcd = unorm_prevFCD16(fcdTrieIndex, fcdHighStart, start, src);
+
+ 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 code unit from the string at a given offset
+ * Handles both normal and iterative cases.
+ * No error checking - caller beware!
+ */
+static inline
+UChar peekCodeUnit(collIterate *source, int32_t offset) {
+ if(source->pos != NULL) {
+ return *(source->pos + offset);
+ } else if(source->iterator != NULL) {
+ UChar32 c;
+ if(offset != 0) {
+ source->iterator->move(source->iterator, offset, UITER_CURRENT);
+ c = source->iterator->next(source->iterator);
+ source->iterator->move(source->iterator, -offset-1, UITER_CURRENT);
+ } else {
+ c = source->iterator->current(source->iterator);
+ }
+ return c >= 0 ? (UChar)c : 0xfffd; // If the caller works properly, we should never see c<0.
+ } else {
+ return 0xfffd;
+ }
+}
+
+// Code point version. Treats the offset as a _code point_ delta.
+// We cannot use U16_FWD_1_UNSAFE and similar because we might not have well-formed UTF-16.
+// We cannot use U16_FWD_1 and similar because we do not know the start and limit of the buffer.
+static inline
+UChar32 peekCodePoint(collIterate *source, int32_t offset) {
+ UChar32 c;
+ if(source->pos != NULL) {
+ const UChar *p = source->pos;
+ if(offset >= 0) {
+ // Skip forward over (offset-1) code points.
+ while(--offset >= 0) {
+ if(U16_IS_LEAD(*p++) && U16_IS_TRAIL(*p)) {
+ ++p;
+ }
+ }
+ // Read the code point there.
+ c = *p++;
+ UChar trail;
+ if(U16_IS_LEAD(c) && U16_IS_TRAIL(trail = *p)) {
+ c = U16_GET_SUPPLEMENTARY(c, trail);
+ }
+ } else /* offset<0 */ {
+ // Skip backward over (offset-1) code points.
+ while(++offset < 0) {
+ if(U16_IS_TRAIL(*--p) && U16_IS_LEAD(*(p - 1))) {
+ --p;
+ }
+ }
+ // Read the code point before that.
+ c = *--p;
+ UChar lead;
+ if(U16_IS_TRAIL(c) && U16_IS_LEAD(lead = *(p - 1))) {
+ c = U16_GET_SUPPLEMENTARY(lead, c);
+ }
+ }
+ } else if(source->iterator != NULL) {
+ if(offset >= 0) {
+ // Skip forward over (offset-1) code points.
+ int32_t fwd = offset;
+ while(fwd-- > 0) {
+ uiter_next32(source->iterator);
+ }
+ // Read the code point there.
+ c = uiter_current32(source->iterator);
+ // Return to the starting point, skipping backward over (offset-1) code points.
+ while(offset-- > 0) {
+ uiter_previous32(source->iterator);
+ }
+ } else /* offset<0 */ {
+ // Read backward, reading offset code points, remember only the last-read one.
+ int32_t back = offset;
+ do {
+ c = uiter_previous32(source->iterator);
+ } while(++back < 0);
+ // Return to the starting position, skipping forward over offset code points.
+ do {
+ uiter_next32(source->iterator);
+ } while(++offset < 0);
+ }
+ } else {
+ c = U_SENTINEL;
+ }
+ return c;
+}
+
+/**
+* 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->offsetReturn != NULL) {
+ if (data->offsetRepeatCount > 0) {
+ data->offsetRepeatCount -= 1;
+ } else {
+ if (data->offsetReturn == data->offsetBuffer) {
+ data->offsetReturn = NULL;
+ data->offsetStore = data->offsetBuffer;
+ } else {
+ data->offsetReturn -= 1;
+ }
+ }
+ }
+
+ if ((data->extendCEs && data->toReturn > data->extendCEs) ||
+ (!data->extendCEs && data->toReturn > data->CEs))
+ {
+ data->toReturn -= 1;
+ result = *(data->toReturn);
+ if (data->CEs == data->toReturn || data->extendCEs == data->toReturn) {
+ data->CEpos = data->toReturn;
+ }
+ }
+ else {
+ UChar ch = 0;
+
+ do {
+ /*
+ 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.
+ */
+ data->flags = data->origFlags;
+ data->offsetRepeatValue = 0;
+
+ if (data->fcdPosition == NULL) {
+ data->pos = data->string;
+ return UCOL_NO_MORE_CES;
+ }
+ else {
+ data->pos = data->fcdPosition + 1;
+ }
+
+ 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 {
+ // Always use UCA for [3400..9FFF], [AC00..D7AF]
+ // **** [FA0E..FA2F] ?? ****
+ if ((data->flags & UCOL_FORCE_HAN_IMPLICIT) != 0 &&
+ (ch >= 0x3400 && ch <= 0xD7AF)) {
+ if (ch > 0x9FFF && ch < 0xAC00) {
+ // between the two target ranges; do normal lookup
+ // **** this range is YI, Modifier tone letters, ****
+ // **** Latin-D, Syloti Nagari, Phagas-pa. ****
+ // **** Latin-D might be tailored, so we need to ****
+ // **** do the normal lookup for these guys. ****
+ result = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+ } else {
+ result = UCOL_NOT_FOUND;
+ }
+ } 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);
+ }
+ }
+ }
+ }
+ } while ( result == UCOL_IGNORABLE && ch >= UCOL_FIRST_HANGUL && ch <= UCOL_LAST_HANGUL );
+
+ 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;
+ IInit_collIterate(coll, &u, 1, &colIt, status);
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ return ucol_IGetNextCE(coll, &colIt, status);
+}
+
+/**
+* Inserts the argument character into the end of the buffer pushing back the
+* null terminator.
+* @param data collIterate struct data
+* @param ch character to be appended
+* @return the position of the new addition
+*/
+static
+inline const UChar * insertBufferEnd(collIterate *data, UChar ch)
+{
+ int32_t oldLength = data->writableBuffer.length();
+ return data->writableBuffer.append(ch).getTerminatedBuffer() + oldLength;
+}
+
+/**
+* Inserts the argument string into the end of the buffer pushing back the
+* null terminator.
+* @param data collIterate struct data
+* @param string to be appended
+* @param length of the string to be appended
+* @return the position of the new addition
+*/
+static
+inline const UChar * insertBufferEnd(collIterate *data, const UChar *str, int32_t length)
+{
+ int32_t oldLength = data->writableBuffer.length();
+ return data->writableBuffer.append(str, length).getTerminatedBuffer() + oldLength;
+}
+
+/**
+* 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)
+{
+ int32_t strsize;
+ UErrorCode status = U_ZERO_ERROR;
+ /* because the pointer points to the next character */
+ const UChar *pStart = data->pos - 1;
+ const UChar *pEnd;
+
+ if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
+ data->writableBuffer.setTo(*(pStart - 1));
+ strsize = 1;
+ }
+ else {
+ strsize = data->writableBuffer.length();
+ }
+
+ pEnd = data->fcdPosition;
+
+ data->writableBuffer.append(
+ data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)(pEnd - pStart)), status));
+ if(U_FAILURE(status)) {
+ return;
+ }
+
+ data->pos = data->writableBuffer.getTerminatedBuffer() + 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);
+ //}
+
+ 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->fcdPosition)) + 1;
+ // Check if data->pos received a null pointer
+ if (data->pos == NULL) {
+ return (UChar)-1; // Return to indicate error.
+ }
+ return *(data->fcdPosition ++);
+ }
+ 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 = (int32_t)(data->fcdPosition - data->pos + 1);
+ data->pos = insertBufferEnd(data, data->pos - 1, length);
+ // Check if data->pos received a null pointer
+ if (data->pos == NULL) {
+ return (UChar)-1; // Return to indicate error.
+ }
+ 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, ch) + 1;
+ // Check if data->pos received a null pointer
+ if (data->pos == NULL) {
+ return (UChar)-1; // Return to indicate error.
+ }
+ }
+
+ /* 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
+*/
+static
+inline void setDiscontiguosAttribute(collIterate *source, const UnicodeString &buffer)
+{
+ /* 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. */
+ if (source->flags & UCOL_ITER_INNORMBUF) {
+ int32_t replaceLength = source->pos - source->writableBuffer.getBuffer();
+ source->writableBuffer.replace(0, replaceLength, buffer);
+ }
+ 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);
+ source->writableBuffer = buffer;
+ }
+
+ source->pos = source->writableBuffer.getTerminatedBuffer();
+}
+
+/**
+* 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 */
+ const UChar *temppos = source->pos;
+ UnicodeString buffer;
+ const UChar *tempconstart = constart;
+ uint8_t tempflags = source->flags;
+ UBool multicontraction = FALSE;
+ collIterateState discState;
+
+ backupState(source, &discState);
+
+ buffer.setTo(peekCodePoint(source, -1));
+ for (;;) {
+ UChar *UCharOffset;
+ UChar schar,
+ tchar;
+ uint32_t result;
+
+ if (((source->flags & UCOL_ITER_HASLEN) && source->pos >= source->endp)
+ || (peekCodeUnit(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(peekCodePoint(source, 0)) == 0) {
+ //u_getCombiningClass(*(source->pos)) == 0) {
+ //constart = (UChar *)coll->image + getContractOffset(CE);
+ if (multicontraction) {
+ source->pos = temppos - 1;
+ setDiscontiguosAttribute(source, buffer);
+ 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 */
+ buffer.append(schar);
+ continue;
+ }
+ else {
+ if (u_getCombiningClass(schar) ==
+ u_getCombiningClass(peekCodePoint(source, -2))) {
+ buffer.append(schar);
+ continue;
+ }
+ result = *(coll->contractionCEs +
+ (UCharOffset - coll->contractionIndex));
+ }
+
+ 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;
+ }
+ } else {
+ setDiscontiguosAttribute(source, buffer);
+ 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));
+}
+
+/* now uses Mark's getImplicitPrimary code */
+static
+inline uint32_t getImplicit(UChar32 cp, collIterate *collationSource) {
+ uint32_t r = uprv_uca_getImplicitPrimary(cp);
+ *(collationSource->CEpos++) = ((r & 0x0000FFFF)<<16) | 0x000000C0;
+ collationSource->offsetRepeatCount += 1;
+ 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 ch character to be appended
+*/
+static
+inline void insertBufferFront(collIterate *data, UChar ch)
+{
+ data->pos = data->writableBuffer.setCharAt(0, ch).insert(0, (UChar)0).getTerminatedBuffer() + 2;
+}
+
+/**
+* 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)
+{
+ const UChar *pEnd = data->pos + 1; /* End normalize + 1 */
+ const UChar *pStart;
+
+ UnicodeString endOfBuffer;
+ if (data->flags & UCOL_ITER_HASLEN) {
+ /*
+ normalization buffer not used yet, we'll pull down the next
+ character into the end of the buffer
+ */
+ endOfBuffer.setTo(*pEnd);
+ }
+ else {
+ endOfBuffer.setTo(data->writableBuffer, 1); // after the leading NUL
+ }
+
+ if (data->fcdPosition == NULL) {
+ pStart = data->string;
+ }
+ else {
+ pStart = data->fcdPosition + 1;
+ }
+ int32_t normLen =
+ data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)(pEnd - pStart)),
+ data->writableBuffer,
+ *status).
+ length();
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ /*
+ this puts the null termination infront of the normalized string instead
+ of the end
+ */
+ data->pos =
+ data->writableBuffer.insert(0, (UChar)0).append(endOfBuffer).getTerminatedBuffer() +
+ 1 + normLen;
+ 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;
+ const UChar *start;
+ UBool innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
+ 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->fcdPosition==NULL)||(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->fcdPosition));
+ data->fcdPosition = NULL;
+ return *(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
+ */
+ const 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, ch);
+ data->fcdPosition --;
+ }
+
+ return ch;
+}
+
+/* This function handles the special CEs like contractions, expansions, surrogates, Thai */
+/* It is called by getNextCE */
+
+/* The following should be even */
+#define UCOL_MAX_DIGITS_FOR_NUMBER 254
+
+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 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.
+ // in order to do the proper detection, we
+ // need to see if we're dealing with a supplementary
+ /* We test whether the next two char are surrogate pairs.
+ * This test is done if the iterator is not NULL.
+ * If there is no surrogate pair, the iterator
+ * goes back one if needed. */
+ UChar32 miss = schar;
+ if (source->iterator) {
+ UChar32 surrNextChar; /* the next char in the iteration to test */
+ int32_t prevPos; /* holds the previous position before move forward of the source iterator */
+ if(U16_IS_LEAD(schar) && source->iterator->hasNext(source->iterator)) {
+ prevPos = source->iterator->index;
+ surrNextChar = getNextNormalizedChar(source);
+ if (U16_IS_TRAIL(surrNextChar)) {
+ miss = U16_GET_SUPPLEMENTARY(schar, surrNextChar);
+ } else if (prevPos < source->iterator->index){
+ goBackOne(source);
+ }
+ }
+ } else if (U16_IS_LEAD(schar)) {
+ 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;
+ source->offsetRepeatCount += 1;
+ 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++;
+ //source->offsetRepeatCount = -1;
+
+ 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++;
+ source->offsetRepeatCount += 1;
+ }
+ } else { /* else, we do */
+ while(*CEOffset != 0) {
+ *(source->CEpos++) = *CEOffset++;
+ source->offsetRepeatCount += 1;
+ }
+ }
+
+ 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,0};
+ UChar32 char32 = 0;
+ int32_t digVal = 0;
+
+ uint32_t digIndx = 0;
+ uint32_t endIndex = 0;
+ uint32_t trailingZeroIndex = 0;
+
+ uint8_t collateVal = 0;
+
+ UBool nonZeroValReached = FALSE;
+
+ uint8_t numTempBuf[UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3]; // I just need a temporary place to store my generated CEs.
+ /*
+ 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. No longer needed;
+ // at this point digIndx now has a max value of UCOL_MAX_DIGITS_FOR_NUMBER
+ // (it has been pre-incremented) so we just ensure that numTempBuf is big enough
+ // (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3).
+
+ // 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 || digIndx > UCOL_MAX_DIGITS_FOR_NUMBER){
+ // 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)
+ {
+ uint32_t primWeight = numTempBuf[i++] << 8;
+ if ( i < endIndex)
+ primWeight |= numTempBuf[i++];
+ *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
+ }
+
+ } 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 */
+ case IMPLICIT_TAG: /* everything that is not defined otherwise */
+ /* UCA is filled with these. Tailorings are NOT_FOUND */
+ return getImplicit(cp, source);
+ case CJK_IMPLICIT_TAG: /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
+ // TODO: remove CJK_IMPLICIT_TAG completely - handled by the getImplicit
+ return getImplicit(cp, source);
+ case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
+ {
+ static const uint32_t
+ SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
+ //const uint32_t LCount = 19;
+ static const uint32_t VCount = 21;
+ static 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
+ UChar *buffer = source->writableBuffer.getBuffer(4);
+ int32_t bufferLength;
+ buffer[0] = (UChar)L;
+ buffer[1] = (UChar)V;
+ if (T != TBase) {
+ buffer[2] = (UChar)T;
+ bufferLength = 3;
+ } else {
+ bufferLength = 2;
+ }
+ source->writableBuffer.releaseBuffer(bufferLength);
+
+ // Indicate where to continue in main input string after exhausting the writableBuffer
+ source->fcdPosition = source->pos;
+
+ source->pos = source->writableBuffer.getTerminatedBuffer();
+ source->origFlags = source->flags;
+ source->flags |= UCOL_ITER_INNORMBUF;
+ source->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+
+ return(UCOL_IGNORABLE);
+ }
+ }
+ 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 treat it like an unassigned code point. */
+ {
+ 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 UCOL_NOT_FOUND;
+ } 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 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 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);
+ }
+ return UCOL_NOT_FOUND;
+ case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
+ return UCOL_NOT_FOUND; /* broken surrogate sequence */
+ 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) {
+ uint32_t r = uprv_uca_getImplicitPrimary(cp);
+
+ *(collationSource->CEpos++) = (r & UCOL_PRIMARYMASK) | 0x00000505;
+ collationSource->toReturn = collationSource->CEpos;
+
+ // **** doesn't work if using iterator ****
+ if (collationSource->flags & UCOL_ITER_INNORMBUF) {
+ collationSource->offsetRepeatCount = 1;
+ } else {
+ int32_t firstOffset = (int32_t)(collationSource->pos - collationSource->string);
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ collationSource->appendOffset(firstOffset, errorCode);
+ collationSource->appendOffset(firstOffset + 1, errorCode);
+
+ collationSource->offsetReturn = collationSource->offsetStore - 1;
+ *(collationSource->offsetBuffer) = firstOffset;
+ if (collationSource->offsetReturn == collationSource->offsetBuffer) {
+ collationSource->offsetStore = collationSource->offsetBuffer;
+ }
+ }
+
+ 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;
+ int32_t CECount = 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 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_SURROGATE(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_SURROGATE_LEAD(schar) && U16_IS_LEAD(lead = getPrevNormalizedChar(source, status))) {
+ isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, lead);
+ if(isSpecial(isZeroCE) && 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, treat like unassigned
+ return UCOL_NOT_FOUND;
+ }
+ } else {
+ // lone surrogate at the beggining, treat like unassigned
+ return UCOL_NOT_FOUND;
+ }
+ }
+ // 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 = peekCodeUnit(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 = (int32_t)(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++;
+
+ int32_t offsetBias;
+
+ // **** doesn't work if using iterator ****
+ if (source->flags & UCOL_ITER_INNORMBUF) {
+ offsetBias = -1;
+ } else {
+ offsetBias = (int32_t)(source->pos - source->string);
+ }
+
+ /* 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;
+ int32_t rawOffset;
+
+ IInit_collIterate(coll, UCharOffset, noChars, &temp, status);
+ if(U_FAILURE(*status)) {
+ return UCOL_NULLORDER;
+ }
+ temp.flags &= ~UCOL_ITER_NORM;
+ temp.flags |= source->flags & UCOL_FORCE_HAN_IMPLICIT;
+
+ rawOffset = (int32_t)(temp.pos - temp.string); // should always be zero?
+ CE = ucol_IGetNextCE(coll, &temp, status);
+
+ if (source->extendCEs) {
+ endCEBuffer = source->extendCEs + source->extendCEsSize;
+ CECount = (int32_t)((source->CEpos - source->extendCEs)/sizeof(uint32_t));
+ } else {
+ endCEBuffer = source->CEs + UCOL_EXPAND_CE_BUFFER_SIZE;
+ CECount = (int32_t)((source->CEpos - source->CEs)/sizeof(uint32_t));
+ }
+
+ while (CE != UCOL_NO_MORE_CES) {
+ *(source->CEpos ++) = CE;
+
+ if (offsetBias >= 0) {
+ source->appendOffset(rawOffset + offsetBias, *status);
+ }
+
+ CECount++;
+ if (source->CEpos == endCEBuffer) {
+ /* ran out of CE space, reallocate to new buffer.
+ If reallocation fails, reset pointers and bail out,
+ there's no guarantee of the right character position after
+ this bail*/
+ if (!increaseCEsCapacity(source)) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+ endCEBuffer = source->extendCEs + source->extendCEsSize;
+ }
+
+ if ((temp.flags & UCOL_ITER_INNORMBUF) != 0) {
+ rawOffset = (int32_t)(temp.fcdPosition - temp.string);
+ } else {
+ rawOffset = (int32_t)(temp.pos - temp.string);
+ }
+
+ CE = ucol_IGetNextCE(coll, &temp, status);
+ }
+
+ if (strbuffer != buffer) {
+ uprv_free(strbuffer);
+ }
+ if (U_FAILURE(*status)) {
+ return (uint32_t)UCOL_NULLORDER;
+ }
+
+ if (source->offsetRepeatValue != 0) {
+ if (CECount > noChars) {
+ source->offsetRepeatCount += temp.offsetRepeatCount;
+ } else {
+ // **** does this really skip the right offsets? ****
+ source->offsetReturn -= (noChars - CECount);
+ }
+ }
+
+ if (offsetBias >= 0) {
+ source->offsetReturn = source->offsetStore - 1;
+ if (source->offsetReturn == source->offsetBuffer) {
+ source->offsetStore = source->offsetBuffer;
+ }
+ }
+
+ 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;
+
+ if (source->flags & UCOL_ITER_INNORMBUF) {
+ source->offsetRepeatCount = 1;
+ } else {
+ int32_t firstOffset = (int32_t)(source->pos - source->string);
+
+ source->appendOffset(firstOffset, *status);
+ source->appendOffset(firstOffset + 1, *status);
+
+ source->offsetReturn = source->offsetStore - 1;
+ *(source->offsetBuffer) = firstOffset;
+ if (source->offsetReturn == source->offsetBuffer) {
+ source->offsetStore = source->offsetBuffer;
+ }
+ }
+
+
+ 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
+ */
+ int32_t firstOffset = (int32_t)(source->pos - source->string);
+
+ // **** doesn't work if using iterator ****
+ if (source->offsetReturn != NULL) {
+ if (! (source->flags & UCOL_ITER_INNORMBUF) && source->offsetReturn == source->offsetBuffer) {
+ source->offsetStore = source->offsetBuffer;
+ }else {
+ firstOffset = -1;
+ }
+ }
+
+ /* 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++;
+
+ if (firstOffset >= 0) {
+ source->appendOffset(firstOffset + 1, *status);
+ }
+ }
+ } else {
+ /* else, we do */
+ while (*CEOffset != 0) {
+ *(source->CEpos ++) = *CEOffset ++;
+
+ if (firstOffset >= 0) {
+ source->appendOffset(firstOffset + 1, *status);
+ }
+ }
+ }
+
+ if (firstOffset >= 0) {
+ source->offsetReturn = source->offsetStore - 1;
+ *(source->offsetBuffer) = firstOffset;
+ if (source->offsetReturn == source->offsetBuffer) {
+ source->offsetStore = source->offsetBuffer;
+ }
+ } else {
+ source->offsetRepeatCount += size - 1;
+ }
+
+ 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 i; /* general counter */
+
+ if (source->coll->numericCollation == UCOL_ON){
+ uint32_t digIndx = 0;
+ uint32_t endIndex = 0;
+ uint32_t leadingZeroIndex = 0;
+ uint32_t trailingZeroCount = 0;
+
+ uint8_t collateVal = 0;
+
+ UBool nonZeroValReached = FALSE;
+
+ uint8_t numTempBuf[UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2]; // I just need a temporary place to store my generated CEs.
+ /*
+ 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...
+ */
+ /*
+ We need to break up the digit string into collection elements of UCOL_MAX_DIGITS_FOR_NUMBER or less,
+ with any chunks smaller than that being on the right end of the digit string - i.e. the first collation
+ element we process when going backward. To determine how long that chunk might be, we may need to make
+ two passes through the loop that collects digits - one to see how long the string is (and how much is
+ leading zeros) to determine the length of that right-hand chunk, and a second (if the whole string has
+ more than UCOL_MAX_DIGITS_FOR_NUMBER non-leading-zero digits) to actually process that collation
+ element chunk after resetting the state to the initialState at the right side of the digit string.
+ */
+ uint32_t ceLimit = 0;
+ UChar initial_ch = ch;
+ collIterateState initialState = {0,0,0,0,0,0,0,0,0};
+ backupState(source, &initialState);
+
+ for(;;) {
+ collIterateState state = {0,0,0,0,0,0,0,0,0};
+ UChar32 char32 = 0;
+ int32_t digVal = 0;
+
+ 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. No longer needed;
+ // at this point the largest value of digIndx when we need to save data in numTempBuf
+ // is UCOL_MAX_DIGITS_FOR_NUMBER-1 (digIndx is post-incremented) so we just ensure
+ // that numTempBuf is big enough (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2).
+
+ // 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;
+
+ // The first pass through, digIndx may exceed the limit, but in that case
+ // we no longer care about numTempBuf contents since they will be discarded
+ if ( digIndx < UCOL_MAX_DIGITS_FOR_NUMBER ) {
+ 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 || (ceLimit > 0 && (digIndx + trailingZeroCount) >= ceLimit)) {
+ 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 (digIndx + trailingZeroCount <= UCOL_MAX_DIGITS_FOR_NUMBER) {
+ // our collation element is not too big, go ahead and finish with it
+ break;
+ }
+ // our digit string is too long for a collation element;
+ // set the limit for it, reset the state and begin again
+ ceLimit = (digIndx + trailingZeroCount) % UCOL_MAX_DIGITS_FOR_NUMBER;
+ if ( ceLimit == 0 ) {
+ ceLimit = UCOL_MAX_DIGITS_FOR_NUMBER;
+ }
+ ch = initial_ch;
+ loadState(source, &initialState, FALSE);
+ digIndx = endIndex = leadingZeroIndex = trailingZeroCount = 0;
+ collateVal = 0;
+ nonZeroValReached = FALSE;
+ }
+
+ if (! nonZeroValReached) {
+ 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 half of endIndex, rounded up.
+ int32_t size = (endIndex+1)/2;
+ if(!ensureCEsCapacity(source, size)) {
+ return UCOL_NULLORDER;
+ }
+ *(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) {
+ uint32_t primWeight = numTempBuf[i--] << 8;
+ if ( i >= 2)
+ primWeight |= numTempBuf[i--];
+ *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
+ }
+
+ 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*/
+ {
+ static const uint32_t
+ SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
+ //const uint32_t LCount = 19;
+ static const uint32_t VCount = 21;
+ static 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;
+
+ int32_t firstOffset = (int32_t)(source->pos - source->string);
+ source->appendOffset(firstOffset, *status);
+
+ /*
+ * 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);
+ source->appendOffset(firstOffset + 1, *status);
+
+ if (T != TBase) {
+ *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
+ source->appendOffset(firstOffset + 1, *status);
+ }
+
+ source->toReturn = source->CEpos - 1;
+
+ source->offsetReturn = source->offsetStore - 1;
+ if (source->offsetReturn == source->offsetBuffer) {
+ source->offsetStore = source->offsetBuffer;
+ }
+
+ 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
+ UChar *tempbuffer = source->writableBuffer.getBuffer(5);
+ int32_t tempbufferLength, jamoOffset;
+ tempbuffer[0] = 0;
+ tempbuffer[1] = (UChar)L;
+ tempbuffer[2] = (UChar)V;
+ if (T != TBase) {
+ tempbuffer[3] = (UChar)T;
+ tempbufferLength = 4;
+ } else {
+ tempbufferLength = 3;
+ }
+ source->writableBuffer.releaseBuffer(tempbufferLength);
+
+ // Indicate where to continue in main input string after exhausting the writableBuffer
+ if (source->pos == source->string) {
+ jamoOffset = 0;
+ source->fcdPosition = NULL;
+ } else {
+ jamoOffset = source->pos - source->string;
+ source->fcdPosition = source->pos-1;
+ }
+
+ // Append offsets for the additional chars
+ // (not the 0, and not the L whose offsets match the original Hangul)
+ int32_t jamoRemaining = tempbufferLength - 2;
+ jamoOffset++; // appended offsets should match end of original Hangul
+ while (jamoRemaining-- > 0) {
+ source->appendOffset(jamoOffset, *status);
+ }
+
+ source->offsetRepeatValue = jamoOffset;
+
+ source->offsetReturn = source->offsetStore - 1;
+ if (source->offsetReturn == source->offsetBuffer) {
+ source->offsetStore = source->offsetBuffer;
+ }
+
+ source->pos = source->writableBuffer.getTerminatedBuffer() + tempbufferLength;
+ source->origFlags = source->flags;
+ source->flags |= UCOL_ITER_INNORMBUF;
+ source->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+
+ return(UCOL_IGNORABLE);
+ }
+ }
+
+ case IMPLICIT_TAG: /* everything that is not defined otherwise */
+ return getPrevImplicit(ch, 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 SURROGATE_TAG: /* This is a surrogate pair */
+ /* essentially an engaged lead surrogate. */
+ /* if you have encountered it here, it means that a */
+ /* broken sequence was encountered and this is an error */
+ return UCOL_NOT_FOUND;
+
+ case LEAD_SURROGATE_TAG: /* D800-DBFF*/
+ return UCOL_NOT_FOUND; /* broken surrogate sequence */
+
+ case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
+ {
+ UChar32 cp = 0;
+ UChar prevChar;
+ const UChar *prev;
+ if (isAtStartPrevIterate(source)) {
+ /* we are at the start of the string, wrong place to be at */
+ return UCOL_NOT_FOUND;
+ }
+ if (source->pos != source->writableBuffer.getBuffer()) {
+ 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 UCOL_NOT_FOUND; /* like unassigned */
+ }
+
+ return getPrevImplicit(cp, 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 */
+/* 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;
+}
+
+U_NAMESPACE_BEGIN
+
+class SortKeyByteSink : public ByteSink {
+public:
+ static const uint32_t FILL_ORIGINAL_BUFFER = 1;
+ static const uint32_t DONT_GROW = 2;
+ SortKeyByteSink(char *dest, int32_t destCapacity, uint32_t flags=0)
+ : ownedBuffer_(NULL), buffer_(dest), capacity_(destCapacity),
+ appended_(0),
+ fill_(flags & FILL_ORIGINAL_BUFFER),
+ grow_((flags & DONT_GROW) == 0) {
+ if (buffer_ == NULL || capacity_ < 0) {
+ buffer_ = reinterpret_cast<char *>(&lastResortByte_);
+ capacity_ = 0;
+ }
+ }
+ virtual ~SortKeyByteSink() { uprv_free(ownedBuffer_); }
+
+ virtual void Append(const char *bytes, int32_t n);
+ void Append(const uint8_t *bytes, int32_t n) { Append(reinterpret_cast<const char *>(bytes), n); }
+ void Append(uint8_t b) {
+ if (appended_ < capacity_) {
+ buffer_[appended_++] = (char)b;
+ } else {
+ Append(&b, 1);
+ }
+ }
+ void Append(uint8_t b1, uint8_t b2) {
+ int32_t a2 = appended_ + 2;
+ if (a2 <= capacity_) {
+ buffer_[appended_] = (char)b1;
+ buffer_[appended_ + 1] = (char)b2;
+ appended_ = a2;
+ } else {
+ char bytes[2] = { (char)b1, (char)b2 };
+ Append(bytes, 2);
+ }
+ }
+ void Append(const SortKeyByteSink &other) { Append(other.buffer_, other.appended_); }
+ virtual char *GetAppendBuffer(int32_t min_capacity,
+ int32_t desired_capacity_hint,
+ char *scratch, int32_t scratch_capacity,
+ int32_t *result_capacity);
+ int32_t NumberOfBytesAppended() const { return appended_; }
+ uint8_t &LastByte() {
+ if (buffer_ != NULL && appended_ > 0) {
+ return reinterpret_cast<uint8_t *>(buffer_)[appended_ - 1];
+ } else {
+ return lastResortByte_;
+ }
+ }
+ uint8_t *GetLastFewBytes(int32_t n) {
+ if (buffer_ != NULL && appended_ >= n) {
+ return reinterpret_cast<uint8_t *>(buffer_) + appended_ - n;
+ } else {
+ return NULL;
+ }
+ }
+ char *GetBuffer() { return buffer_; }
+ uint8_t *GetUnsignedBuffer() { return reinterpret_cast<uint8_t *>(buffer_); }
+ uint8_t *OrphanUnsignedBuffer(int32_t &orphanedCapacity);
+ UBool IsOk() const { return buffer_ != NULL; } // otherwise out-of-memory
+
+private:
+ SortKeyByteSink(const SortKeyByteSink &); // copy constructor not implemented
+ SortKeyByteSink &operator=(const SortKeyByteSink &); // assignment operator not implemented
+
+ UBool Resize(int32_t appendCapacity, int32_t length);
+ void SetNotOk() {
+ buffer_ = NULL;
+ capacity_ = 0;
+ }
+
+ static uint8_t lastResortByte_; // last-resort return value from LastByte()
+
+ char *ownedBuffer_;
+ char *buffer_;
+ int32_t capacity_;
+ int32_t appended_;
+ UBool fill_;
+ UBool grow_;
+};
+
+uint8_t SortKeyByteSink::lastResortByte_ = 0;
+
+void
+SortKeyByteSink::Append(const char *bytes, int32_t n) {
+ if (n <= 0) {
+ return;
+ }
+ int32_t length = appended_;
+ appended_ += n;
+ if ((buffer_ + length) == bytes) {
+ return; // the caller used GetAppendBuffer() and wrote the bytes already
+ }
+ if (buffer_ == NULL) {
+ return; // allocation failed before already
+ }
+ int32_t available = capacity_ - length;
+ if (bytes == NULL) {
+ // assume that the caller failed to allocate memory
+ if (fill_) {
+ if (n > available) {
+ n = available;
+ }
+ uprv_memset(buffer_, 0, n);
+ }
+ SetNotOk(); // propagate the out-of-memory error
+ return;
+ }
+ if (n > available) {
+ if (fill_ && available > 0) {
+ // Fill the original buffer completely.
+ uprv_memcpy(buffer_ + length, bytes, available);
+ bytes += available;
+ length += available;
+ n -= available;
+ available = 0;
+ }
+ fill_ = FALSE;
+ if (!Resize(n, length)) {
+ SetNotOk();
+ return;
+ }
+ }
+ uprv_memcpy(buffer_ + length, bytes, n);
+}
+
+char *
+SortKeyByteSink::GetAppendBuffer(int32_t min_capacity,
+ int32_t desired_capacity_hint,
+ char *scratch,
+ int32_t scratch_capacity,
+ int32_t *result_capacity) {
+ if (min_capacity < 1 || scratch_capacity < min_capacity) {
+ *result_capacity = 0;
+ return NULL;
+ }
+ int32_t available = capacity_ - appended_;
+ if (available >= min_capacity) {
+ *result_capacity = available;
+ return buffer_ + appended_;
+ } else if (Resize(desired_capacity_hint, appended_)) {
+ *result_capacity = capacity_ - appended_;
+ return buffer_ + appended_;
+ } else {
+ *result_capacity = scratch_capacity;
+ return scratch;
+ }
+}
+
+UBool
+SortKeyByteSink::Resize(int32_t appendCapacity, int32_t length) {
+ if (!grow_) {
+ return FALSE;
+ }
+ int32_t newCapacity = 2 * capacity_;
+ int32_t altCapacity = length + 2 * appendCapacity;
+ if (newCapacity < altCapacity) {
+ newCapacity = altCapacity;
+ }
+ if (newCapacity < 1024) {
+ newCapacity = 1024;
+ }
+ char *newBuffer = (char *)uprv_malloc(newCapacity);
+ if (newBuffer == NULL) {
+ return FALSE;
+ }
+ uprv_memcpy(newBuffer, buffer_, length);
+ uprv_free(ownedBuffer_);
+ ownedBuffer_ = buffer_ = newBuffer;
+ capacity_ = newCapacity;
+ return TRUE;
+}
+
+uint8_t *
+SortKeyByteSink::OrphanUnsignedBuffer(int32_t &orphanedCapacity) {
+ if (buffer_ == NULL || appended_ == 0) {
+ orphanedCapacity = 0;
+ return NULL;
+ }
+ if (ownedBuffer_ != NULL) {
+ // orphan & forget the ownedBuffer_
+ uint8_t *returnBuffer = reinterpret_cast<uint8_t *>(ownedBuffer_);
+ ownedBuffer_ = buffer_ = NULL;
+ orphanedCapacity = capacity_;
+ capacity_ = appended_ = 0;
+ return returnBuffer;
+ }
+ // clone the buffer_
+ uint8_t *newBuffer = (uint8_t *)uprv_malloc(appended_);
+ if (newBuffer == NULL) {
+ orphanedCapacity = 0;
+ return NULL;
+ }
+ uprv_memcpy(newBuffer, buffer_, appended_);
+ orphanedCapacity = appended_;
+ return newBuffer;
+}
+
+U_NAMESPACE_END
+
+/* 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(...);*/
+
+ SortKeyByteSink sink(reinterpret_cast<char *>(result), resultLength,
+ SortKeyByteSink::FILL_ORIGINAL_BUFFER | SortKeyByteSink::DONT_GROW);
+ coll->sortKeyGen(coll, source, sourceLength, sink, &status);
+ keySize = sink.NumberOfBytesAppended();
+ }
+ 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 *&result, int32_t &resultCapacity,
+ UErrorCode *pErrorCode) {
+ SortKeyByteSink sink(reinterpret_cast<char *>(result), resultCapacity);
+ coll->sortKeyGen(coll, source, sourceLength, sink, pErrorCode);
+ int32_t resultLen = sink.NumberOfBytesAppended();
+ if (U_SUCCESS(*pErrorCode)) {
+ if (!sink.IsOk()) {
+ *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ } else if (result != sink.GetUnsignedBuffer()) {
+ result = sink.OrphanUnsignedBuffer(resultCapacity);
+ }
+ }
+ return resultLen;
+}
+
+// Is this primary weight compressible?
+// Returns false for multi-lead-byte scripts (digits, Latin, Han, implicit).
+// TODO: This should use per-lead-byte flags from FractionalUCA.txt.
+static inline UBool
+isCompressible(const UCollator * /*coll*/, uint8_t primary1) {
+ return UCOL_BYTE_FIRST_NON_LATIN_PRIMARY <= primary1 && primary1 <= maxRegularPrimary;
+}
+
+static
+inline void doCaseShift(SortKeyByteSink &cases, uint32_t &caseShift) {
+ if (caseShift == 0) {
+ cases.Append(UCOL_CASE_BYTE_START);
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+}
+
+// Packs the secondary buffer when processing French locale.
+static void
+packFrench(uint8_t *secondaries, int32_t secsize, SortKeyByteSink &result) {
+ secondaries += secsize; // We read the secondary-level bytes back to front.
+ uint8_t secondary;
+ int32_t count2 = 0;
+ int32_t i = 0;
+ // we use i here since the key size already accounts for terminators, so we'll discard the increment
+ 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) {
+ result.Append((uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2));
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ result.Append((uint8_t)(UCOL_COMMON_TOP2 - (count2-1)));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ result.Append((uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ result.Append((uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ count2 = 0;
+ }
+ result.Append(secondary);
+ }
+ }
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ result.Append((uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ result.Append((uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+}
+
+#define DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY 0
+
+/* This is the sortkey work horse function */
+U_CFUNC void U_CALLCONV
+ucol_calcSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ SortKeyByteSink &result,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return;
+ }
+
+ /* Stack allocated buffers for buffers we use */
+ char second[UCOL_SECONDARY_MAX_BUFFER], tert[UCOL_TERTIARY_MAX_BUFFER];
+ char caseB[UCOL_CASE_MAX_BUFFER], quad[UCOL_QUAD_MAX_BUFFER];
+
+ SortKeyByteSink &primaries = result;
+ SortKeyByteSink secondaries(second, LENGTHOF(second));
+ SortKeyByteSink tertiaries(tert, LENGTHOF(tert));
+ SortKeyByteSink cases(caseB, LENGTHOF(caseB));
+ SortKeyByteSink quads(quad, LENGTHOF(quad));
+
+ UnicodeString normSource;
+
+ 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);
+
+ 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 */
+ int32_t lastSecondaryLength = 0;
+ uint32_t caseShift = 0;
+
+ /* If we need to normalize, we'll do it all at once at the beginning! */
+ const Normalizer2 *norm2;
+ if(compareIdent) {
+ norm2 = Normalizer2Factory::getNFDInstance(*status);
+ } else if(coll->normalizationMode != UCOL_OFF) {
+ norm2 = Normalizer2Factory::getFCDInstance(*status);
+ } else {
+ norm2 = NULL;
+ }
+ if(norm2 != NULL) {
+ normSource.setTo(FALSE, source, len);
+ int32_t qcYesLength = norm2->spanQuickCheckYes(normSource, *status);
+ if(qcYesLength != len) {
+ UnicodeString unnormalized = normSource.tempSubString(qcYesLength);
+ normSource.truncate(qcYesLength);
+ norm2->normalizeSecondAndAppend(normSource, unnormalized, *status);
+ source = normSource.getBuffer();
+ len = normSource.length();
+ }
+ }
+ collIterate s;
+ IInit_collIterate(coll, source, len, &s, status);
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ s.flags &= ~UCOL_ITER_NORM; // source passed the FCD test or else was normalized.
+
+ 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 = coll->tertiaryAddition;
+ uint8_t tertiaryTop = coll->tertiaryTop;
+ uint8_t tertiaryBottom = coll->tertiaryBottom;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+ uint8_t caseBits = 0;
+
+ UBool wasShifted = FALSE;
+ UBool notIsContinuation = FALSE;
+
+ uint32_t count2 = 0, count3 = 0, count4 = 0;
+ 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);
+
+ uint8_t originalPrimary1 = primary1;
+ if(notIsContinuation && coll->leadBytePermutationTable != NULL) {
+ primary1 = coll->leadBytePermutationTable[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.Append((uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4));
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ quads.Append((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.Append(primary1);
+ }
+ if(primary2 != 0) {
+ quads.Append(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 a-z and friends, when primary2 will */
+ /* regular and simple sortkey calc */
+ if(primary1 != UCOL_IGNORABLE) {
+ if(notIsContinuation) {
+ if(leadPrimary == primary1) {
+ primaries.Append(primary2);
+ } else {
+ if(leadPrimary != 0) {
+ primaries.Append((uint8_t)((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN));
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ primaries.Append(primary1);
+ leadPrimary = 0;
+ } else if(isCompressible(coll, originalPrimary1)) {
+ /* compress */
+ primaries.Append(leadPrimary = primary1, primary2);
+ } else {
+ leadPrimary = 0;
+ primaries.Append(primary1, primary2);
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ if(primary2 == UCOL_IGNORABLE) {
+ primaries.Append(primary1);
+ } else {
+ primaries.Append(primary1, primary2);
+ }
+ }
+ }
+
+ 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.Append((uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2));
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ secondaries.Append((uint8_t)(UCOL_COMMON_TOP2 - (count2-1)));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ secondaries.Append((uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ secondaries.Append((uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ count2 = 0;
+ }
+ secondaries.Append(secondary);
+ }
+ } else {
+ /* 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 (lastSecondaryLength > 1) {
+ uint8_t *frenchStartPtr = secondaries.GetLastFewBytes(lastSecondaryLength);
+ if (frenchStartPtr != NULL) {
+ /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
+ uint8_t *frenchEndPtr = frenchStartPtr + lastSecondaryLength - 1;
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ }
+ }
+ lastSecondaryLength = 1;
+ } else {
+ ++lastSecondaryLength;
+ }
+ secondaries.Append(secondary);
+ }
+ }
+
+ 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.LastByte() |= 1 << (--caseShift);
+ } else {
+ cases.LastByte() |= 0 << (--caseShift);
+ /* second bit */
+ doCaseShift(cases, caseShift);
+ cases.LastByte() |= ((caseBits>>6)&1) << (--caseShift);
+ }
+ } else {
+ if((caseBits & 0xC0) == 0) {
+ cases.LastByte() |= 0 << (--caseShift);
+ } else {
+ cases.LastByte() |= 1 << (--caseShift);
+ /* second bit */
+ doCaseShift(cases, caseShift);
+ cases.LastByte() |= ((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.Append((uint8_t)(tertiaryTop - coll->tertiaryTopCount));
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryTop - (count3-1)));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ tertiaries.Append((uint8_t)(tertiaryBottom + coll->tertiaryBottomCount));
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryBottom + (count3-1)));
+ }
+ count3 = 0;
+ }
+ tertiaries.Append(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.Append((uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4));
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ quads.Append((uint8_t)(UCOL_COMMON_BOT4 + (count4-1)));
+ count4 = 0;
+ }
+ quads.Append(UCOL_HIRAGANA_QUAD); // Add the Hiragana
+ } else { // This wasn't Hiragana, so we can continue adding stuff
+ count4++;
+ }
+ }
+ }
+ }
+
+ /* Here, we are generally done with processing */
+ /* bailing out would not be too productive */
+
+ if(U_SUCCESS(*status)) {
+ /* 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.Append((uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ secondaries.Append((uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ result.Append(UCOL_LEVELTERMINATOR);
+ if(!isFrenchSec || !secondaries.IsOk()) {
+ result.Append(secondaries);
+ } else {
+ // If there are any unresolved continuation secondaries,
+ // reverse them here so that we can reverse the whole secondary thing.
+ if (lastSecondaryLength > 1) {
+ uint8_t *frenchStartPtr = secondaries.GetLastFewBytes(lastSecondaryLength);
+ if (frenchStartPtr != NULL) {
+ /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
+ uint8_t *frenchEndPtr = frenchStartPtr + lastSecondaryLength - 1;
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ }
+ }
+ packFrench(secondaries.GetUnsignedBuffer(), secondaries.NumberOfBytesAppended(), result);
+ }
+ }
+
+ if(doCase) {
+ result.Append(UCOL_LEVELTERMINATOR);
+ result.Append(cases);
+ }
+
+ if(compareTer == 0) {
+ if (count3 > 0) {
+ if (coll->tertiaryCommon != UCOL_COMMON_BOT3) {
+ while (count3 >= coll->tertiaryTopCount) {
+ tertiaries.Append((uint8_t)(tertiaryTop - coll->tertiaryTopCount));
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryTop - count3));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ tertiaries.Append((uint8_t)(tertiaryBottom + coll->tertiaryBottomCount));
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryBottom + (count3-1)));
+ }
+ }
+ result.Append(UCOL_LEVELTERMINATOR);
+ result.Append(tertiaries);
+
+ if(compareQuad == 0/*qShifted == TRUE*/) {
+ if(count4 > 0) {
+ while (count4 > UCOL_BOT_COUNT4) {
+ quads.Append((uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4));
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ quads.Append((uint8_t)(UCOL_COMMON_BOT4 + (count4-1)));
+ }
+ result.Append(UCOL_LEVELTERMINATOR);
+ result.Append(quads);
+ }
+
+ if(compareIdent) {
+ result.Append(UCOL_LEVELTERMINATOR);
+ u_writeIdenticalLevelRun(s.string, len, result);
+ }
+ }
+ result.Append(0);
+ }
+
+ /* To avoid memory leak, free the offset buffer if necessary. */
+ ucol_freeOffsetBuffer(&s);
+}
+
+
+U_CFUNC void U_CALLCONV
+ucol_calcSortKeySimpleTertiary(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ SortKeyByteSink &result,
+ UErrorCode *status)
+{
+ U_ALIGN_CODE(16);
+
+ if(U_FAILURE(*status)) {
+ return;
+ }
+
+ /* Stack allocated buffers for buffers we use */
+ char second[UCOL_SECONDARY_MAX_BUFFER], tert[UCOL_TERTIARY_MAX_BUFFER];
+
+ SortKeyByteSink &primaries = result;
+ SortKeyByteSink secondaries(second, LENGTHOF(second));
+ SortKeyByteSink tertiaries(tert, LENGTHOF(tert));
+
+ UnicodeString normSource;
+
+ int32_t len = sourceLength;
+
+ /* If we need to normalize, we'll do it all at once at the beginning! */
+ if(coll->normalizationMode != UCOL_OFF) {
+ normSource.setTo(len < 0, source, len);
+ const Normalizer2 *norm2 = Normalizer2Factory::getFCDInstance(*status);
+ int32_t qcYesLength = norm2->spanQuickCheckYes(normSource, *status);
+ if(qcYesLength != normSource.length()) {
+ UnicodeString unnormalized = normSource.tempSubString(qcYesLength);
+ normSource.truncate(qcYesLength);
+ norm2->normalizeSecondAndAppend(normSource, unnormalized, *status);
+ source = normSource.getBuffer();
+ len = normSource.length();
+ }
+ }
+ collIterate s;
+ IInit_collIterate(coll, (UChar *)source, len, &s, status);
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ s.flags &= ~UCOL_ITER_NORM; // source passed the FCD test or else was normalized.
+
+ 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 = coll->tertiaryAddition;
+ uint8_t tertiaryTop = coll->tertiaryTop;
+ uint8_t tertiaryBottom = coll->tertiaryBottom;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+
+ UBool notIsContinuation = FALSE;
+
+ uint32_t count2 = 0, count3 = 0;
+ uint8_t leadPrimary = 0;
+
+ for(;;) {
+ order = ucol_IGetNextCE(coll, &s, status);
+
+ if(order == 0) {
+ continue;
+ }
+
+ if(order == UCOL_NO_MORE_CES) {
+ 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);
+
+ uint8_t originalPrimary1 = primary1;
+ if (coll->leadBytePermutationTable != NULL && notIsContinuation) {
+ primary1 = coll->leadBytePermutationTable[primary1];
+ }
+
+ /* 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 a-z 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.Append(primary2);
+ } else {
+ if(leadPrimary != 0) {
+ primaries.Append((uint8_t)((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN));
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ primaries.Append(primary1);
+ leadPrimary = 0;
+ } else if(isCompressible(coll, originalPrimary1)) {
+ /* compress */
+ primaries.Append(leadPrimary = primary1, primary2);
+ } else {
+ leadPrimary = 0;
+ primaries.Append(primary1, primary2);
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ if(primary2 == UCOL_IGNORABLE) {
+ primaries.Append(primary1);
+ } else {
+ primaries.Append(primary1, primary2);
+ }
+ }
+ }
+
+ 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.Append((uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2));
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ secondaries.Append((uint8_t)(UCOL_COMMON_TOP2 - (count2-1)));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ secondaries.Append((uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ secondaries.Append((uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ count2 = 0;
+ }
+ secondaries.Append(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.Append((uint8_t)(tertiaryTop - coll->tertiaryTopCount));
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryTop - (count3-1)));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ tertiaries.Append((uint8_t)(tertiaryBottom + coll->tertiaryBottomCount));
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryBottom + (count3-1)));
+ }
+ count3 = 0;
+ }
+ tertiaries.Append(tertiary);
+ }
+ }
+ }
+
+ if(U_SUCCESS(*status)) {
+ /* 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.Append((uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ secondaries.Append((uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ result.Append(UCOL_LEVELTERMINATOR);
+ result.Append(secondaries);
+
+ if (count3 > 0) {
+ if (coll->tertiaryCommon != UCOL_COMMON3_NORMAL) {
+ while (count3 >= coll->tertiaryTopCount) {
+ tertiaries.Append((uint8_t)(tertiaryTop - coll->tertiaryTopCount));
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryTop - count3));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ tertiaries.Append((uint8_t)(tertiaryBottom + coll->tertiaryBottomCount));
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ tertiaries.Append((uint8_t)(tertiaryBottom + (count3-1)));
+ }
+ }
+ result.Append(UCOL_LEVELTERMINATOR);
+ result.Append(tertiaries);
+
+ result.Append(0);
+ }
+
+ /* To avoid memory leak, free the offset buffer if necessary. */
+ ucol_freeOffsetBuffer(&s);
+
+ if (U_SUCCESS(*status) && !result.IsOk()) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+}
+
+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, status);
+ if(U_FAILURE(*status)) {
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+ 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(!isContinuation(CE)){
+ if(coll->leadBytePermutationTable != NULL){
+ CE = (coll->leadBytePermutationTable[CE>>24] << 24) | (CE & 0x00FFFFFF);
+ }
+ }
+ 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(;;) {
+ U_ASSERT(caseShift <= UCOL_CASE_SHIFT_START);
+ 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 (caseShift == 0) {
+ dest[i++] = caseByte;
+ caseShift = UCOL_CASE_SHIFT_START;
+ caseByte = UCOL_CASE_BYTE_START;
+ }
+ 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);
+ }
+
+ /* To avoid memory leak, free the offset buffer if necessary. */
+ ucol_freeOffsetBuffer(&s);
+
+ // 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;
+ UBool continuation = isContinuation(CE);
+ if(!continuation) {
+ 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) {
+ if (coll->leadBytePermutationTable != NULL && !continuation) {
+ primary1 = coll->leadBytePermutationTable[primary1];
+ }
+
+ 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);
+ // Check for null pointer
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ 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;;
+ case SPEC_PROC_TAG:
+ {
+ // 0xB7 is a precontext character defined in UCA5.1, a special
+ // handle is implemeted in order to save LatinOne table for
+ // most locales.
+ if (ch==0xb7) {
+ ucol_addLatinOneEntry(coll, ch, CE, &primShift, &secShift, &terShift);
+ }
+ else {
+ goto cleanup_after_failure;
+ }
+ }
+ 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 = (int8_t)UCOL_FLAG_BIT_MASK_CASE_SW_OFF; /* Should be 0x80 */
+ 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 - coll->tertiaryBottom - 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, status);
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ 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;
+ }
+
+ /* To avoid memory leak, free the offset buffer if necessary. */
+ ucol_freeOffsetBuffer(&s);
+
+ 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;
+ initializeFCD(status);
+ } 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;
+ if(coll->normalizationMode == UCOL_ON) {
+ initializeFCD(status);
+ }
+ } 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);
+}
+
+U_DRAFT int32_t U_EXPORT2
+ucol_getReorderCodes(const UCollator *coll,
+ int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+#ifdef UCOL_DEBUG
+ printf("coll->reorderCodesLength = %d\n", coll->reorderCodesLength);
+ printf("coll->defaultReorderCodesLength = %d\n", coll->defaultReorderCodesLength);
+#endif
+
+ if (coll->reorderCodesLength > destCapacity) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ return coll->reorderCodesLength;
+ }
+ for (int32_t i = 0; i < coll->reorderCodesLength; i++) {
+ dest[i] = coll->reorderCodes[i];
+ }
+ return coll->reorderCodesLength;
+}
+
+U_DRAFT void U_EXPORT2
+ucol_setReorderCodes(UCollator* coll,
+ const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ if (reorderCodesLength < 0 || (reorderCodesLength > 0 && reorderCodes == NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ if (coll->reorderCodes != NULL && coll->freeReorderCodesOnClose == TRUE) {
+ uprv_free(coll->reorderCodes);
+ }
+ coll->reorderCodes = NULL;
+ coll->reorderCodesLength = 0;
+ if (reorderCodesLength == 0) {
+ if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+ return;
+ }
+ coll->reorderCodes = (int32_t*) uprv_malloc(reorderCodesLength * sizeof(int32_t));
+ if (coll->reorderCodes == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ coll->freeReorderCodesOnClose = TRUE;
+ for (int32_t i = 0; i < reorderCodesLength; i++) {
+ coll->reorderCodes[i] = reorderCodes[i];
+ }
+ coll->reorderCodesLength = reorderCodesLength;
+ ucol_buildPermutationTable(coll, status);
+}
+
+U_DRAFT int32_t U_EXPORT2
+ucol_getEquivalentReorderCodes(int32_t reorderCode,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode *pErrorCode) {
+ bool equivalentCodesSet[USCRIPT_CODE_LIMIT];
+ uint16_t leadBytes[256];
+ int leadBytesCount;
+ int leadByteIndex;
+ int16_t reorderCodesForLeadByte[USCRIPT_CODE_LIMIT];
+ int reorderCodesForLeadByteCount;
+ int reorderCodeIndex;
+
+ int32_t equivalentCodesCount = 0;
+ int setIndex;
+
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+
+ if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ uprv_memset(equivalentCodesSet, 0, USCRIPT_CODE_LIMIT * sizeof(bool));
+
+ const UCollator* uca = ucol_initUCA(pErrorCode);
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ leadBytesCount = ucol_getLeadBytesForReorderCode(uca, reorderCode, leadBytes, 256);
+ for (leadByteIndex = 0; leadByteIndex < leadBytesCount; leadByteIndex++) {
+ reorderCodesForLeadByteCount = ucol_getReorderCodesForLeadByte(
+ uca, leadBytes[leadByteIndex], reorderCodesForLeadByte, USCRIPT_CODE_LIMIT);
+ for (reorderCodeIndex = 0; reorderCodeIndex < reorderCodesForLeadByteCount; reorderCodeIndex++) {
+ equivalentCodesSet[reorderCodesForLeadByte[reorderCodeIndex]] = true;
+ }
+ }
+
+ for (setIndex = 0; setIndex < USCRIPT_CODE_LIMIT; setIndex++) {
+ if (equivalentCodesSet[setIndex] == true) {
+ equivalentCodesCount++;
+ }
+ }
+
+ if (destCapacity == 0) {
+ return equivalentCodesCount;
+ }
+
+ equivalentCodesCount = 0;
+ for (setIndex = 0; setIndex < USCRIPT_CODE_LIMIT; setIndex++) {
+ if (equivalentCodesSet[setIndex] == true) {
+ dest[equivalentCodesCount++] = setIndex;
+ if (equivalentCodesCount >= destCapacity) {
+ break;
+ }
+ }
+ }
+ return equivalentCodesCount;
+}
+
+
+/****************************************************************************/
+/* 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) {
+ /* Include the minor number when getting the UCA version. (major & 1f) << 3 | (minor & 7) */
+ versionInfo[3] = (coll->UCA->image->UCAVersion[0] & 0x1f) << 3 | (coll->UCA->image->UCAVersion[1] & 0x07);
+ } 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. */
+/* */
+/* Comparison must be done on NFD normalized strings. */
+/* FCD is not good enough. */
+
+static
+UCollationResult ucol_checkIdent(collIterate *sColl, collIterate *tColl, UBool normalize, UErrorCode *status)
+{
+ // 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.
+ int32_t comparison;
+
+ if (sColl->flags & UCOL_USE_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 stackNormIter1[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ UAlignedMemory stackNormIter2[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ 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 {
+ int32_t sLen = (sColl->flags & UCOL_ITER_HASLEN) ? (int32_t)(sColl->endp - sColl->string) : -1;
+ const UChar *sBuf = sColl->string;
+ int32_t tLen = (tColl->flags & UCOL_ITER_HASLEN) ? (int32_t)(tColl->endp - tColl->string) : -1;
+ const UChar *tBuf = tColl->string;
+
+ if (normalize) {
+ *status = U_ZERO_ERROR;
+ // Note: We could use Normalizer::compare() or similar, but for short strings
+ // which may not be in FCD it might be faster to just NFD them.
+ // Note: spanQuickCheckYes() + normalizeSecondAndAppend() rather than
+ // NFD'ing immediately might be faster for long strings,
+ // but string comparison is usually done on relatively short strings.
+ sColl->nfd->normalize(UnicodeString((sColl->flags & UCOL_ITER_HASLEN) == 0, sBuf, sLen),
+ sColl->writableBuffer,
+ *status);
+ tColl->nfd->normalize(UnicodeString((tColl->flags & UCOL_ITER_HASLEN) == 0, tBuf, tLen),
+ tColl->writableBuffer,
+ *status);
+ if(U_FAILURE(*status)) {
+ return UCOL_LESS;
+ }
+ comparison = sColl->writableBuffer.compareCodePointOrder(tColl->writableBuffer);
+ } else {
+ comparison = u_strCompare(sBuf, sLen, tBuf, tLen, TRUE);
+ }
+ }
+
+ 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, UErrorCode *status) {
+ uint32_t oldSize;
+ uint32_t newSize;
+ uint32_t *newBuf;
+
+ ci->flags |= UCOL_ITER_ALLOCATED;
+ oldSize = (uint32_t)(b->pos - b->buf);
+ newSize = oldSize * 2;
+ newBuf = (uint32_t *)uprv_malloc(newSize * sizeof(uint32_t));
+ if(newBuf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else {
+ 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, UErrorCode *status) {
+ if (b->pos == b->endp) {
+ ucol_CEBuf_Expand(b, ci, status);
+ }
+ if (U_SUCCESS(*status)) {
+ *(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;
+ const UChar *source = NULL;
+ const UChar *target = NULL;
+ int32_t result = UCOL_EQUAL;
+ UnicodeString sourceString, targetString;
+ int32_t sourceLength;
+ int32_t targetLength;
+
+ if(sColl->flags & UCOL_USE_ITERATOR) {
+ sColl->iterator->move(sColl->iterator, 0, UITER_START);
+ tColl->iterator->move(tColl->iterator, 0, UITER_START);
+ UChar32 c;
+ while((c=sColl->iterator->next(sColl->iterator))>=0) {
+ sourceString.append((UChar)c);
+ }
+ while((c=tColl->iterator->next(tColl->iterator))>=0) {
+ targetString.append((UChar)c);
+ }
+ source = sourceString.getBuffer();
+ sourceLength = sourceString.length();
+ target = targetString.getBuffer();
+ targetLength = targetString.length();
+ } else { // no iterators
+ sourceLength = (sColl->flags&UCOL_ITER_HASLEN)?(int32_t)(sColl->endp-sColl->string):-1;
+ targetLength = (tColl->flags&UCOL_ITER_HASLEN)?(int32_t)(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 UCollationResult
+ucol_strcollRegular(collIterate *sColl, collIterate *tColl, 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, status);
+ // 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, status);
+ 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 {
+ // only need to check one for continuation
+ // if one is then the other must be or the preceding CE would be a prefix of the other
+ if (coll->leadBytePermutationTable != NULL && !isContinuation(sOrder)) {
+ sOrder = (coll->leadBytePermutationTable[sOrder>>24] << 24) | (sOrder & 0x00FFFFFF);
+ tOrder = (coll->leadBytePermutationTable[tOrder>>24] << 24) | (tOrder & 0x00FFFFFF);
+ }
+ // 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, status);
+ 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, status);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
+ break;
+ }
+ } else { /* Just lower level values */
+ if(sInShifted) {
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
+ continue;
+ }
+ }
+ } else { /* regular */
+ if(coll->leadBytePermutationTable != NULL){
+ sOrder = (coll->leadBytePermutationTable[sOrder>>24] << 24) | (sOrder & 0x00FFFFFF);
+ }
+ if((sOrder & UCOL_PRIMARYMASK) > LVT) {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
+ break;
+ } else {
+ if((sOrder & UCOL_PRIMARYMASK) > 0) {
+ sInShifted = TRUE;
+ sOrder &= UCOL_PRIMARYMASK;
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
+ 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, status);
+ 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, status);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
+ break;
+ }
+ } else { /* Just lower level values */
+ if(tInShifted) {
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
+ continue;
+ }
+ }
+ } else { /* regular */
+ if(coll->leadBytePermutationTable != NULL){
+ tOrder = (coll->leadBytePermutationTable[tOrder>>24] << 24) | (tOrder & 0x00FFFFFF);
+ }
+ if((tOrder & UCOL_PRIMARYMASK) > LVT) {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
+ break;
+ } else {
+ if((tOrder & UCOL_PRIMARYMASK) > 0) {
+ tInShifted = TRUE;
+ tOrder &= UCOL_PRIMARYMASK;
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
+ 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 == NULL) {
+ 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 = NULL;
+ secS = 0; /* Fetch a fresh CE before the continuation sequence. */
+ continue;
+ }
+ }
+ secS &= UCOL_SECONDARYMASK; /* remove the continuation bit */
+ }
+
+ while(secT == 0 && tCE >= tCEs.buf) {
+ if(tCESave == NULL) {
+ 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 = NULL;
+ secT = 0; /* Fetch a fresh CE before the continuation sequence. */
+ 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) {
+ if (sCEs.buf != sCEs.localArray ) {
+ uprv_free(sCEs.buf);
+ }
+ if (tCEs.buf != tCEs.localArray ) {
+ uprv_free(tCEs.buf);
+ }
+ }
+
+ return result;
+}
+
+static UCollationResult
+ucol_strcollRegular(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ const UChar *target, int32_t targetLength,
+ UErrorCode *status) {
+ collIterate sColl, tColl;
+ // Preparing the context objects for iterating over strings
+ IInit_collIterate(coll, source, sourceLength, &sColl, status);
+ IInit_collIterate(coll, target, targetLength, &tColl, status);
+ if(U_FAILURE(*status)) {
+ return UCOL_LESS;
+ }
+ return ucol_strcollRegular(&sColl, &tColl, status);
+}
+
+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 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");
+ 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");
+ 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");
+ 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");
+ 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
+ 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;
+}
+
+
+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;
+ IInit_collIterate(coll, NULL, -1, &sColl, status);
+ IInit_collIterate(coll, NULL, -1, &tColl, status);
+ if(U_FAILURE(*status)) {
+ UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
+ return UCOL_EQUAL;
+ }
+ // 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;
+
+ sColl.iterator = sIter;
+ sColl.flags |= UCOL_USE_ITERATOR;
+ 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);
+ }
+
+ if(source == NULL || target == NULL) {
+ // do not crash, but return. Should have
+ // status argument to return error.
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+
+ /* Quick check if source and target are same strings. */
+ /* They should either both be NULL terminated or the explicit length should be set on both. */
+ if (source==target && sourceLength==targetLength) {
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+
+ /* 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.
+ // Scan through any leading equal portion.
+ while (*pSrc == *pTarg && *pSrc != 0) {
+ pSrc++;
+ pTarg++;
+ }
+ if (*pSrc == 0 && *pTarg == 0) {
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+ equalLength = (int32_t)(pSrc - source);
+ }
+ else
+ {
+ // One or both strings has an explicit length.
+ 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 = (int32_t)(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. */
+
+ // These values should already be set by the code above.
+ //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;
+ }
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCollationResult returnVal;
+ if(!coll->latinOneUse || (sourceLength > 0 && *source&0xff00) || (targetLength > 0 && *target&0xff00)) {
+ returnVal = ucol_strcollRegular(coll, source, sourceLength, target, targetLength, &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));
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.cpp
new file mode 100644
index 00000000000..e6c5048d61c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.cpp
@@ -0,0 +1,1417 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2011, 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/udata.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/uscript.h"
+#include "unicode/ustring.h"
+#include "normalizer2impl.h"
+#include "ucol_bld.h"
+#include "ucol_elm.h"
+#include "ucol_cnt.h"
+#include "ucln_in.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.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);
+ return (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]) {
+ } 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;
+}
+
+static 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; \
+ } \
+}
+
+static uint32_t ucol_getNextGenerated(ucolCEGenerator *g, UErrorCode *status) {
+ if(U_SUCCESS(*status)) {
+ g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+ }
+ return g->current;
+}
+
+static 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;
+}
+
+static 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) {
+ if (low < UCOL_COMMON_TOP2<<24 ) {
+ // Override if low range is less than UCOL_COMMON_TOP2.
+ low = UCOL_COMMON_TOP2<<24;
+ }
+ high = 0xFFFFFFFF;
+ } else {
+ // Override if low range is less than UCOL_COMMON_BOT3.
+ if ( low < UCOL_COMMON_BOT3<<24 ) {
+ low = UCOL_COMMON_BOT3<<24;
+ }
+ high = 0x40000000;
+ }
+ break;
+ }
+ if(s<0) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ if(low < 0x02000000) {
+ // We must not use CE weight byte 02, so we set it as the minimum lower bound.
+ // See http://site.icu-project.org/design/collation/bytes
+ low = 0x02000000;
+ }
+
+ 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(0x3041 <= c && c <= 0x30FA) { /* 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(0x3041 <= c && c <= 0x30FA) { /* 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;
+}
+
+U_NAMESPACE_BEGIN
+
+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, status);
+ 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 if(U_SUCCESS(*status)) {
+ 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;
+ UChar32 fcdHighStart;
+ const uint16_t *fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, 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.rulesToParseHdl = &(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, status);
+
+ 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) {
+ for(i = 0; i<el.cSize; i++) {
+ if(UCOL_ISJAMO(el.cPoints[i])) {
+ t->image->jamoSpecial = TRUE;
+ }
+ }
+ if (!src->buildCCTabFlag && el.cSize > 0) {
+ // Check the trailing canonical combining class (tccc) of the last character.
+ const UChar *s = el.cPoints + el.cSize;
+ uint16_t fcd = unorm_prevFCD16(fcdTrieIndex, fcdHighStart, el.cPoints, s);
+ if ((fcd & 0xff) != 0) {
+ 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, status);
+ 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);
+ }
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+U_CFUNC 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);
+ // Check for null pointer
+ if (ucaEl == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ 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 (!needToAdd && isPrefix(tailoredCE) && *(conts+1)==0) {
+ UCAElements elm;
+ elm.cPoints = el.uchars;
+ elm.noOfCEs = 0;
+ elm.uchars[0] = *conts;
+ elm.uchars[1] = 0;
+ elm.cSize = 1;
+ elm.prefixChars[0] = *(conts+2);
+ elm.isThai = FALSE;
+ elm.prefix = elm.prefixChars;
+ elm.prefixSize = 1;
+ UCAElements *prefixEnt=(UCAElements *)uhash_get(t->prefixLookup, &elm);
+ if ((prefixEnt==NULL) || *(prefixEnt->prefix)!=*(conts+2)) {
+ needToAdd = TRUE;
+ }
+ }
+ if(src->removeSet != NULL && uset_contains(src->removeSet, *conts)) {
+ needToAdd = FALSE;
+ }
+
+ if(needToAdd == TRUE) { // we need to add if this contraction is not tailored.
+ if (*(conts+1) != 0) { // contractions
+ 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);
+ }
+ else { // pre-context character
+ UChar str[4] = { 0 };
+ int32_t len=0;
+ int32_t preKeyLen=0;
+
+ el.cPoints = el.uchars;
+ el.noOfCEs = 0;
+ el.uchars[0] = *conts;
+ el.uchars[1] = 0;
+ el.cSize = 1;
+ el.prefixChars[0] = *(conts+2);
+ el.prefix = el.prefixChars;
+ el.prefixSize = 1;
+ if (el.prefixChars[0]!=0) {
+ // get CE of prefix character first
+ str[0]=el.prefixChars[0];
+ str[1]=0;
+ ucol_setText(ucaEl, str, 1, status);
+ while ((int32_t)(el.CEs[el.noOfCEs] = ucol_next(ucaEl, status))
+ != UCOL_NULLORDER) {
+ preKeyLen++; // count number of keys for prefix character
+ }
+ str[len++] = el.prefixChars[0];
+ }
+
+ str[len++] = el.uchars[0];
+ str[len]=0;
+ ucol_setText(ucaEl, str, len, status);
+ // Skip the keys for prefix character, then copy the rest to el.
+ while ((preKeyLen-->0) &&
+ (int32_t)(el.CEs[el.noOfCEs] = ucol_next(ucaEl, status)) != UCOL_NULLORDER) {
+ continue;
+ }
+
+ }
+ 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, NULL, 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(U_ICUDATA_COLL, 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) {
+ invUCA_DATA_MEM = result;
+ _staticInvUCA = newInvUCA;
+ 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;
+}
+
+/* This is the data that is used for non-script reordering codes. These _must_ be kept
+ * in order that they are to be applied as defaults and in synch with the UColReorderCode enum.
+ */
+static const char* ReorderingTokenNames[] = {
+ "SPACE",
+ "PUNCT",
+ "SYMBOL",
+ "CURRENCY",
+ "DIGIT",
+ NULL
+};
+
+static void toUpper(const char* src, char* dst, uint32_t length) {
+ for (uint32_t i = 0; *src != '\0' && i < length - 1; ++src, ++dst, ++i) {
+ *dst = toupper(*src);
+ }
+ *dst = '\0';
+}
+
+U_INTERNAL int32_t U_EXPORT2
+ucol_findReorderingEntry(const char* name) {
+ char buffer[32];
+ toUpper(name, buffer, 32);
+ for (uint32_t entry = 0; ReorderingTokenNames[entry] != NULL; entry++) {
+ if (uprv_strcmp(buffer, ReorderingTokenNames[entry]) == 0) {
+ return entry + UCOL_REORDER_CODE_FIRST;
+ }
+ }
+ return USCRIPT_INVALID_CODE;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.h
new file mode 100644
index 00000000000..e722c6cc79d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_bld.h
@@ -0,0 +1,59 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2010, 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_wgt.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;
+
+U_CFUNC uint32_t U_EXPORT2 ucol_getCEStrengthDifference(uint32_t CE, uint32_t contCE,
+ uint32_t prevCE, uint32_t prevContCE);
+
+U_INTERNAL int32_t U_EXPORT2 ucol_findReorderingEntry(const char* name);
+
+/*#endif*/ /* #if !UCONFIG_NO_COLLATION_BUILDER */
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.cpp
new file mode 100644
index 00000000000..7c274b763e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.cpp
@@ -0,0 +1,587 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2001-2008, 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);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ }
+
+ 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);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ }
+
+ 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 (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ }
+
+ 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-4.8.1/i18n/ucol_cnt.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.h
new file mode 100644
index 00000000000..f6dfcd77b26
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_cnt.h
@@ -0,0 +1,102 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2008, 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 "utrie.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-4.8.1/i18n/ucol_elm.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_elm.cpp
new file mode 100644
index 00000000000..bb686eed6f3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_elm.cpp
@@ -0,0 +1,2064 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2010, 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 "normalizer2impl.h"
+#include "ucol_elm.h"
+#include "ucol_tok.h"
+#include "ucol_cnt.h"
+#include "unicode/caniter.h"
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+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 (U_FAILURE(*status)) {
+ goto allocation_failure;
+ }
+ t->prefixLookup = uhash_open(prefixLookupHash, prefixLookupComp, NULL, status);
+ if (U_FAILURE(*status)) {
+ goto allocation_failure;
+ }
+ uhash_setValueDeleter(t->prefixLookup, uhash_freeBlock);
+
+ t->contractions = uprv_cnttab_open(t->mapping, status);
+ if (U_FAILURE(*status)) {
+ goto cleanup;
+ }
+
+ /* copy UCA's maxexpansion and merge as we go along */
+ if (UCA != NULL) {
+ /* adding an extra initial value for easier manipulation */
+ maxet->size = (int32_t)(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:
+ *status = U_MEMORY_ALLOCATION_ERROR;
+cleanup:
+ uprv_uca_closeTempTable(t);
+ return NULL;
+}
+
+static 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;
+ goto cleanup;
+ }
+ 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;
+ goto cleanup;
+ }
+ 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);
+ // Check for cloning failure.
+ if (r->contractions == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ 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;
+ goto cleanup;
+ }
+ 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);
+ /* test for NULL */
+ if (r->maxExpansions->endExpansionCE == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ uprv_memset(r->maxExpansions->endExpansionCE, 0xDB, sizeof(uint32_t)*t->maxExpansions->size);
+ 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);
+ /* test for NULL */
+ if (r->maxExpansions->expansionCESize == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ uprv_memset(r->maxExpansions->expansionCESize, 0xDB, sizeof(uint8_t)*t->maxExpansions->size);
+ 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;
+ goto cleanup;
+ }
+ 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;
+ goto cleanup;
+ }
+ 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;
+ goto cleanup;
+ }
+ 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;
+ goto cleanup;
+ }
+ 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;
+ goto cleanup;
+ }
+ uprv_memcpy(r->contrEndCP, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE);
+ }
+
+ r->UCA = t->UCA;
+ r->image = t->image;
+ r->options = t->options;
+
+ return r;
+cleanup:
+ uprv_uca_closeTempTable(t);
+ return NULL;
+}
+
+
+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));
+ if (neweece == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ maxexpansion->endExpansionCE = neweece;
+
+ uint8_t *neweces = (uint8_t *)uprv_realloc(maxexpansion->expansionCESize,
+ 2 * maxexpansion->size * sizeof(uint8_t));
+ if (neweces == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ 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 = (int)(start - pendexpansionce);
+ }
+ else if (*limit == endexpansion) {
+ result = (int)(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 = (int)((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 *fcdTrieIndex;
+ UChar32 fcdHighStart;
+ UBool buildCMTable = (t->cmLookup==NULL); // flag for building combining class table
+ UChar *cm=NULL;
+ uint16_t index[256];
+ int32_t count=0;
+ fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, 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(fcdTrieIndex, 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);
+ if ((element->prefixSize!=0) && (!isSpecial(CE) || (getCETag(CE)!=IMPLICIT_TAG))) {
+ UCAElements *origElem = (UCAElements *)uprv_malloc(sizeof(UCAElements));
+ /* test for NULL */
+ if (origElem== NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ /* copy the original UCA value */
+ origElem->prefixSize = 0;
+ origElem->prefix = NULL;
+ origElem->cPoints = origElem->uchars;
+ origElem->cPoints[0] = element->cPoints[0];
+ origElem->cSize = 1;
+ origElem->CEs[0]=CE;
+ origElem->mapCE=CE;
+ origElem->noOfCEs=1;
+ uprv_uca_finalizeAddition(t, origElem, status);
+ uprv_free(origElem);
+ }
+#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
+UBool 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);
+ }
+ return TRUE;
+}
+
+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;
+ const Normalizer2Impl *nfcImpl;
+ UnicodeSet *closed;
+ 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 decompBuffer[4];
+ const UChar *decomp;
+ int32_t noOfDec = 0;
+
+ UChar32 u32 = 0;
+ UChar comp[2];
+ uint32_t len = 0;
+
+ for(u32 = start; u32 < limit; u32++) {
+ decomp = ((enumStruct *)context)->nfcImpl->
+ getDecomposition(u32, decompBuffer, noOfDec);
+ //if((noOfDec = unorm_normalize(comp, len, UNORM_NFD, 0, decomp, 256, status)) > 1
+ //|| (noOfDec == 1 && *decomp != (UChar)u32))
+ if(decomp != NULL)
+ {
+ len = 0;
+ U16_APPEND_UNSAFE(comp, len, u32);
+ if(ucol_strcoll(tempColl, comp, len, decomp, noOfDec) != UCOL_EQUAL) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "Closure: U+%04X -> ", u32);
+ UChar32 c;
+ int32_t i = 0;
+ while(i < noOfDec) {
+ U16_NEXT(decomp, i, noOfDec, c);
+ fprintf(stderr, "%04X ", c);
+ }
+ fprintf(stderr, "\n");
+ // print CEs for code point vs. decomposition
+ fprintf(stderr, "U+%04X CEs: ", u32);
+ UCollationElements *iter = ucol_openElements(tempColl, comp, len, status);
+ int32_t ce;
+ while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) {
+ fprintf(stderr, "%08X ", ce);
+ }
+ fprintf(stderr, "\nDecomp CEs: ");
+ ucol_setText(iter, decomp, noOfDec, status);
+ while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) {
+ fprintf(stderr, "%08X ", ce);
+ }
+ fprintf(stderr, "\n");
+ ucol_closeElements(iter);
+#endif
+ if(((enumStruct *)context)->closed != NULL) {
+ ((enumStruct *)context)->closed->add(u32);
+ }
+ ((enumStruct *)context)->noOfClosures++;
+ el.cPoints = (UChar *)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;
+ UChar32 fcdHighStart;
+ const uint16_t *fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, status);
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ int16_t curClass = (unorm_getFCD16(fcdTrieIndex, 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;
+ 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;
+ UChar32 fcdHighStart;
+ const uint16_t *fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, status);
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ int16_t maxIndex = (unorm_getFCD16(fcdTrieIndex, 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(fcdTrieIndex, cMark) & 0xff);
+ maxIndex = (int32_t)index[(unorm_getFCD16(fcdTrieIndex, 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(fcdTrieIndex, 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(fcdTrieIndex, 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_CFUNC int32_t U_EXPORT2
+uprv_uca_canonicalClosure(tempUCATable *t,
+ UColTokenParser *src,
+ UnicodeSet *closed,
+ UErrorCode *status)
+{
+ enumStruct context;
+ context.closed = closed;
+ context.noOfClosures = 0;
+ UCAElements el;
+ UColToken *tok;
+ uint32_t i = 0, j = 0;
+ UChar baseChar, firstCM;
+ UChar32 fcdHighStart;
+ const uint16_t *fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, status);
+ context.nfcImpl=Normalizer2Factory::getNFCImpl(*status);
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ UCollator *tempColl = NULL;
+ tempUCATable *tempTable = uprv_uca_cloneTempTable(t, status);
+ // Check for null pointer
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ 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->ucaRules = NULL;
+ tempColl->actualLocale = 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);
+ // Check for null pointer
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ 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(fcdTrieIndex, 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-4.8.1/i18n/ucol_elm.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_elm.h
new file mode 100644
index 00000000000..9c85b197f17
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_elm.h
@@ -0,0 +1,146 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2000-2010, 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 "unicode/uniset.h"
+#include "ucol_tok.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#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 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 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,
+ U_NAMESPACE_QUALIFIER UnicodeSet *closed, UErrorCode *status);
+
+U_CDECL_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_imp.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_imp.h
new file mode 100644
index 00000000000..6637be8efa8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_imp.h
@@ -0,0 +1,1171 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1998-2011, 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
+
+#ifdef XP_CPLUSPLUS
+#include "unicode/normalizer2.h"
+#include "unicode/unistr.h"
+#endif
+#include "unicode/ucol.h"
+#include "utrie.h"
+#include "cmemory.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)
+ *
+ * uint32_t offset to the reordering code to lead CE byte remapping table
+ * uint32_t offset to the lead CE byte to reordering code mapping table
+ *
+ * uint8_t reserved[76]; - 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)3)
+#define UCA_FORMAT_VERSION_1 0
+#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
+
+UCOL_CASE_MAX_BUFFER as previously defined above was too small. A single collation element can
+generate two caseShift values, and UCOL_CASE_SHIFT_START (=7) caseShift values are compressed into
+one byte. UCOL_MAX_BUFFER should effectively be multipled by 2/UCOL_CASE_SHIFT_START (2/7), not 1/4.
+Perhaps UCOL_CASE_SHIFT_START used to be 8; then this would have been correct. We should dynamically
+define UCOL_CASE_MAX_BUFFER in terms of both UCOL_MAX_BUFFER and UCOL_CASE_SHIFT_START. Since
+UCOL_CASE_SHIFT_START is defined lower down, we move the real definition of UCOL_CASE_MAX_BUFFER
+after it, further down.
+*/
+#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 HAVE MALLOC FALLBACK. If you make it too small, you'll get into performance 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 64
+
+/* This is the size to increase the buffer for expansion CE's */
+#define UCOL_EXPAND_CE_BUFFER_EXTEND_SIZE 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 UCOL_FORCE_HAN_IMPLICIT 128
+
+#define NFC_ZERO_CC_BLOCK_LIMIT_ 0x300
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+typedef struct collIterate : public UMemory {
+ const UChar *string; /* Original string */
+ /* UChar *start; Pointer to the start of the source string. Either points to string
+ or to writableBuffer */
+ const UChar *endp; /* string end ptr. Is undefined for null terminated strings */
+ const 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 */
+
+ int32_t *offsetReturn; /* This is the offset to return, if non-NULL */
+ int32_t *offsetStore; /* This is the pointer for storing offsets */
+ int32_t offsetRepeatCount; /* Repeat stored offset if non-zero */
+ int32_t offsetRepeatValue; /* offset value to repeat */
+
+ UnicodeString writableBuffer;
+ const UChar *fcdPosition; /* Position in the original string to continue FCD check from. */
+ const UCollator *coll;
+ const Normalizer2 *nfd;
+ uint8_t flags;
+ uint8_t origFlags;
+ uint32_t *extendCEs; /* This is use if CEs is not big enough */
+ int32_t extendCEsSize; /* Holds the size of the dynamic CEs buffer */
+ uint32_t CEs[UCOL_EXPAND_CE_BUFFER_SIZE]; /* This is where we store CEs */
+
+ int32_t *offsetBuffer; /* A dynamic buffer to hold offsets */
+ int32_t offsetBufferSize; /* The size of the offset buffer */
+
+ UCharIterator *iterator;
+ /*int32_t iteratorIndex;*/
+
+ // The offsetBuffer should probably be a UVector32, but helper functions
+ // are an improvement over duplicated code.
+ void appendOffset(int32_t offset, UErrorCode &errorCode);
+} collIterate;
+
+U_NAMESPACE_END
+
+#else
+
+typedef struct collIterate collIterate;
+
+#endif
+
+#define paddedsize(something) ((something)+((((something)%4)!=0)?(4-(something)%4):0))
+#define headersize (paddedsize(sizeof(UCATableHeader))+paddedsize(sizeof(UColOptionSet)))
+
+/*
+struct used internally in getSpecial*CE.
+data similar to collIterate.
+*/
+struct collIterateState {
+ const UChar *pos; /* This is position in the string. Can be to original or writable buf */
+ const UChar *returnPos;
+ const UChar *fcdPosition; /* Position in the original string to continue FCD check from. */
+ const UChar *bufferaddress; /* address of the normalization buffer */
+ int32_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,
+ U_NAMESPACE_QUALIFIER collIterate *s, UErrorCode *status);
+
+/* Internal functions for C test code. */
+U_CAPI U_NAMESPACE_QUALIFIER collIterate * U_EXPORT2
+uprv_new_collIterate(UErrorCode *status);
+
+U_CAPI void U_EXPORT2
+uprv_delete_collIterate(U_NAMESPACE_QUALIFIER collIterate *s);
+
+/* @return s->pos == s->endp */
+U_CAPI UBool U_EXPORT2
+uprv_collIterateAtEnd(U_NAMESPACE_QUALIFIER collIterate *s);
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+struct UCollationPCE;
+typedef struct UCollationPCE UCollationPCE;
+
+U_NAMESPACE_END
+
+struct UCollationElements : public U_NAMESPACE_QUALIFIER UMemory
+{
+ /**
+ * Struct wrapper for source data
+ */
+ U_NAMESPACE_QUALIFIER collIterate iteratordata_;
+ /**
+ * Indicates if this data has been reset.
+ */
+ UBool reset_;
+ /**
+ * Indicates if the data should be deleted.
+ */
+ UBool isWritable;
+
+/**
+ * Data for getNextProcessed, getPreviousProcessed.
+ */
+ U_NAMESPACE_QUALIFIER UCollationPCE *pce;
+};
+
+#else
+/*opaque type*/
+struct UCollationElements;
+#endif
+
+U_CAPI void U_EXPORT2
+uprv_init_pce(const struct UCollationElements *elems);
+
+#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
+
+/*
+The definition of UCOL_CASE_MAX_BUFFER is moved down here so it can use UCOL_CASE_SHIFT_START.
+
+A single collation element can generate two caseShift values, and UCOL_CASE_SHIFT_START caseShift
+values are compressed into one byte. The UCOL_CASE_MAX_BUFFER should effectively be UCOL_MAX_BUFFER
+multipled by 2/UCOL_CASE_SHIFT_START, with suitable rounding up.
+*/
+#define UCOL_CASE_MAX_BUFFER (((2*UCOL_MAX_BUFFER) + UCOL_CASE_SHIFT_START - 1)/UCOL_CASE_SHIFT_START)
+
+#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)))
+
+/* Han character ranges */
+#define UCOL_FIRST_HAN 0x4E00
+#define UCOL_LAST_HAN 0x9FFF
+#define UCOL_FIRST_HAN_A 0x3400
+#define UCOL_LAST_HAN_A 0x4DBF
+#define UCOL_FIRST_HAN_COMPAT 0xFAE0
+#define UCOL_LAST_HAN_COMPAT 0xFA2F
+
+/* Han extension B is in plane 2 */
+#define UCOL_FIRST_HAN_B 0x20000
+#define UCOL_LAST_HAN_B 0x2A6DF
+
+/* Hangul range */
+#define UCOL_FIRST_HANGUL 0xAC00
+#define UCOL_LAST_HANGUL 0xD7AF
+
+/* Jamo ranges */
+#define UCOL_FIRST_L_JAMO 0x1100
+#define UCOL_FIRST_V_JAMO 0x1161
+#define UCOL_FIRST_T_JAMO 0x11A8
+#define UCOL_LAST_T_JAMO 0x11F9
+
+
+#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,
+ U_NAMESPACE_QUALIFIER collIterate *source, UErrorCode *status);
+
+U_CFUNC
+uint32_t ucol_prv_getSpecialPrevCE(const UCollator *coll, UChar ch, uint32_t CE,
+ U_NAMESPACE_QUALIFIER collIterate *source, UErrorCode *status);
+U_CAPI uint32_t U_EXPORT2 ucol_getNextCE(const UCollator *coll,
+ U_NAMESPACE_QUALIFIER collIterate *collationSource, UErrorCode *status);
+U_CFUNC uint32_t U_EXPORT2 ucol_getPrevCE(const UCollator *coll,
+ U_NAMESPACE_QUALIFIER collIterate *collationSource,
+ UErrorCode *status);
+/* get some memory */
+void *ucol_getABuffer(const UCollator *coll, uint32_t size);
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+class SortKeyByteSink;
+
+U_NAMESPACE_END
+
+/* 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 *&result, int32_t &resultCapacity,
+ UErrorCode *pErrorCode);
+
+typedef void U_CALLCONV
+SortKeyGenerator(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ U_NAMESPACE_QUALIFIER SortKeyByteSink &result,
+ UErrorCode *status);
+
+/* worker function for generating sortkeys */
+U_CFUNC
+void U_CALLCONV
+ucol_calcSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ U_NAMESPACE_QUALIFIER SortKeyByteSink &result,
+ UErrorCode *status);
+
+U_CFUNC
+void U_CALLCONV
+ucol_calcSortKeySimpleTertiary(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ U_NAMESPACE_QUALIFIER SortKeyByteSink &result,
+ UErrorCode *status);
+
+#else
+
+typedef void U_CALLCONV
+SortKeyGenerator(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ void *result,
+ UErrorCode *status);
+
+#endif
+
+/**
+ * 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_CFUNC 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, char *actualLocaleToAdopt);
+
+#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.
+ * See also http://site.icu-project.org/design/collation/bytes */
+/* 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,
+ /* TODO: Make the following values dynamic since they change with almost every UCA version. */
+ UCOL_CODAN_PLACEHOLDER = 0x12,
+ UCOL_BYTE_FIRST_NON_LATIN_PRIMARY = 0x5B,
+ 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 */
+ uint32_t scriptToLeadByte; /* offset to script to lead collation byte mapping data */
+ uint32_t leadByteToScript; /* offset to lead collation byte to script mapping data */
+ uint8_t reserved[76]; /* 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 void U_CALLCONV
+ResourceCleaner(UCollator *coll);
+
+
+struct UCollator {
+ UColOptionSet *options;
+ SortKeyGenerator *sortKeyGen;
+ uint32_t *latinOneCEs;
+ char* actualLocale;
+ char* validLocale;
+ char* requestedLocale;
+ const UChar *rules;
+ const UChar *ucaRules;
+ const UCollator *UCA;
+ const UCATableHeader *image;
+ UTrie mapping;
+ const uint32_t *latinOneMapping;
+ const uint32_t *expansion;
+ const UChar *contractionIndex;
+ const uint32_t *contractionCEs;
+
+ 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 freeDefaultReorderCodesOnClose;
+ UBool freeReorderCodesOnClose;
+ UBool freeLeadBytePermutationTableOnClose;
+
+ UBool latinOneUse;
+ UBool latinOneRegenTable;
+ UBool latinOneFailed;
+
+ int8_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 */
+ int32_t* defaultReorderCodes;
+ int32_t defaultReorderCodesLength;
+ int32_t* reorderCodes;
+ int32_t reorderCodesLength;
+ uint8_t* leadBytePermutationTable;
+};
+
+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(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);
+
+typedef const UChar* GetCollationRulesFunction(void* context, const char* locale, const char* type, int32_t* pLength, UErrorCode* status);
+
+U_CAPI UCollator* U_EXPORT2
+ucol_openRulesForImport( const UChar *rules,
+ int32_t rulesLength,
+ UColAttributeValue normalizationMode,
+ UCollationStrength strength,
+ UParseError *parseError,
+ GetCollationRulesFunction importFunc,
+ void* context,
+ UErrorCode *status);
+
+
+U_CFUNC void U_EXPORT2
+ucol_buildPermutationTable(UCollator *coll, UErrorCode *status);
+
+U_CFUNC int U_EXPORT2
+ucol_getLeadBytesForReorderCode(const UCollator *uca, int reorderCode, uint16_t* returnLeadBytes, int returnCapacity);
+
+U_CFUNC int U_EXPORT2
+ucol_getReorderCodesForLeadByte(const UCollator *uca, int leadByte, int16_t* returnReorderCodes, int returnCapacity);
+
+#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_SURROGATE(c)) {
+ /* Lead or 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);
+}
+#endif /* XP_CPLUSPLUS */
+
+/* The offsetBuffer in collIterate might need to be freed to avoid memory leaks. */
+void ucol_freeOffsetBuffer(U_NAMESPACE_QUALIFIER collIterate *s);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_res.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_res.cpp
new file mode 100644
index 00000000000..9c42bc7a603
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_res.cpp
@@ -0,0 +1,1388 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2011, 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/uscript.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 "ucln_in.h"
+#include "ustrenum.h"
+#include "putilimp.h"
+#include "utracimp.h"
+#include "cmemory.h"
+#include "uenumimp.h"
+#include "ulist.h"
+
+U_NAMESPACE_USE
+
+static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status);
+
+// 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;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+ucol_res_cleanup(void)
+{
+ if (UCA_DATA_MEM) {
+ udata_close(UCA_DATA_MEM);
+ UCA_DATA_MEM = NULL;
+ }
+ if (_staticUCA) {
+ ucol_close(_staticUCA);
+ _staticUCA = NULL;
+ }
+ return TRUE;
+}
+
+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
+#if UCA_FORMAT_VERSION_1!=0
+ && pInfo->formatVersion[1]>=UCA_FORMAT_VERSION_1
+#endif
+ //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;
+ }
+}
+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) {
+ UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, status);
+
+ if(U_SUCCESS(*status)){
+ UCollator *newUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, status);
+ if(U_SUCCESS(*status)){
+ // Initalize variables for implicit generation
+ uprv_uca_initImplicitConstants(status);
+
+ umtx_lock(NULL);
+ if(_staticUCA == NULL) {
+ UCA_DATA_MEM = result;
+ _staticUCA = newUCA;
+ newUCA = NULL;
+ result = NULL;
+ }
+ umtx_unlock(NULL);
+
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
+ if(newUCA != NULL) {
+ ucol_close(newUCA);
+ udata_close(result);
+ }
+ }else{
+ ucol_close(newUCA);
+ udata_close(result);
+ }
+ }
+ else {
+ udata_close(result);
+ }
+ }
+ return _staticUCA;
+}
+
+U_CAPI void U_EXPORT2
+ucol_forgetUCA(void)
+{
+ _staticUCA = NULL;
+ UCA_DATA_MEM = NULL;
+}
+
+/****************************************************************************/
+/* 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)
+{
+ UErrorCode intStatus = U_ZERO_ERROR;
+ 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) ||
+ !uprv_strcmp(keyBuffer,"default")) { /* Treat 'zz@collation=default' as 'zz'. */
+ // no keyword. we try to find the default setting, which will give us the keyword value
+ 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, collations, status);
+ collations = NULL; // We just reused the collations object as collElem.
+
+ UResourceBundle *binary = NULL;
+ UResourceBundle *reorderRes = 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 (U_FAILURE(*status)) {
+ goto clean;
+ }
+ // if we use UCA, real locale is root
+ ures_close(b);
+ b = ures_open(U_ICUDATA_COLL, "", status);
+ ures_close(collElem);
+ collElem = ures_open(U_ICUDATA_COLL, "", status);
+ if(U_FAILURE(*status)) {
+ goto clean;
+ }
+ result->hasRealData = FALSE;
+ } else if(U_SUCCESS(*status)) {
+ intStatus = U_ZERO_ERROR;
+
+ binary = ures_getByKey(collElem, "%%CollationBin", NULL, &intStatus);
+
+ if(intStatus == 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(intStatus)) { /* otherwise, we'll pick a collation data that exists */
+ int32_t len = 0;
+ const uint8_t *inData = ures_getBinary(binary, &len, status);
+ if(U_FAILURE(*status)) {
+ goto clean;
+ }
+ 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;
+
+ reorderRes = ures_getByKey(collElem, "%%ReorderCodes", NULL, &intStatus);
+ if (U_SUCCESS(intStatus)) {
+ int32_t reorderCodesLen = 0;
+ const int32_t* reorderCodes = ures_getIntVector(reorderRes, &reorderCodesLen, status);
+ if (reorderCodesLen > 0) {
+ ucol_setReorderCodes(result, reorderCodes, reorderCodesLen, status);
+ // copy the reorder codes into the default reorder codes
+ result->defaultReorderCodesLength = result->reorderCodesLength;
+ result->defaultReorderCodes = (int32_t*) uprv_malloc(result->defaultReorderCodesLength * sizeof(int32_t));
+ uprv_memcpy(result->defaultReorderCodes, result->reorderCodes, result->defaultReorderCodesLength * sizeof(int32_t));
+ result->freeDefaultReorderCodesOnClose = TRUE;
+ }
+ if (U_FAILURE(*status)) {
+ goto clean;
+ }
+ }
+ }
+
+ } else { // !U_SUCCESS(binaryStatus)
+ if(U_SUCCESS(*status)) {
+ *status = intStatus; // propagate underlying error
+ }
+ goto clean;
+ }
+ intStatus = U_ZERO_ERROR;
+ result->rules = ures_getStringByKey(collElem, "Sequence", &result->rulesLength, &intStatus);
+ result->freeRulesOnClose = FALSE;
+ } else { /* There is another error, and we're just gonna clean up */
+ goto clean;
+ }
+
+ intStatus = U_ZERO_ERROR;
+ result->ucaRules = ures_getStringByKey(b,"UCARules",NULL,&intStatus);
+
+ if(loc == NULL) {
+ loc = ures_getLocaleByType(b, ULOC_ACTUAL_LOCALE, status);
+ }
+ result->requestedLocale = uprv_strdup(loc);
+ /* test for NULL */
+ if (result->requestedLocale == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto clean;
+ }
+ loc = ures_getLocaleByType(collElem, ULOC_ACTUAL_LOCALE, status);
+ result->actualLocale = uprv_strdup(loc);
+ /* test for NULL */
+ if (result->actualLocale == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto clean;
+ }
+ loc = ures_getLocaleByType(b, ULOC_ACTUAL_LOCALE, status);
+ result->validLocale = uprv_strdup(loc);
+ /* test for NULL */
+ if (result->validLocale == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto clean;
+ }
+
+ ures_close(b);
+ ures_close(collElem);
+ ures_close(binary);
+ ures_close(reorderRes);
+ return result;
+
+clean:
+ ures_close(b);
+ ures_close(collElem);
+ ures_close(binary);
+ ures_close(reorderRes);
+ ucol_close(result);
+ 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;
+
+#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;
+}
+
+
+UCollator*
+ucol_openRulesForImport( const UChar *rules,
+ int32_t rulesLength,
+ UColAttributeValue normalizationMode,
+ UCollationStrength strength,
+ UParseError *parseError,
+ GetCollationRulesFunction importFunc,
+ void* context,
+ UErrorCode *status)
+{
+ UColTokenParser src;
+ UColAttributeValue norm;
+ UParseError tErr;
+
+ if(status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+
+ 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 *result = NULL;
+ UCATableHeader *table = NULL;
+ UCollator *UCA = ucol_initUCA(status);
+
+ if(U_FAILURE(*status)){
+ return NULL;
+ }
+
+ ucol_tok_initTokenList(&src, rules, rulesLength, UCA, importFunc, context, 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", (int)(src.current-src.source));
+ } else {
+ fprintf(stderr, "invalid rule just before offset %i\n", (int)(src.current-src.source));
+ }
+#endif
+ goto cleanup;
+ }
+
+ 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);
+ if (U_FAILURE(*status)) {
+ goto cleanup;
+ }
+ 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);
+ // Check for null result
+ if (U_FAILURE(*status)) {
+ goto cleanup;
+ }
+ // 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);
+ ucol_setReorderCodesFromParser(result, &src, 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->ucaRules = NULL;
+ result->actualLocale = NULL;
+ result->validLocale = NULL;
+ result->requestedLocale = NULL;
+ ucol_buildPermutationTable(result, status);
+ 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 UCollator* U_EXPORT2
+ucol_openRules( const UChar *rules,
+ int32_t rulesLength,
+ UColAttributeValue normalizationMode,
+ UCollationStrength strength,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ return ucol_openRulesForImport(rules,
+ rulesLength,
+ normalizationMode,
+ strength,
+ parseError,
+ ucol_tok_getRulesFromBundle,
+ NULL,
+ status);
+}
+
+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 = coll->ucaRules;
+ if (ucaRules) {
+ UCAlen = u_strlen(ucaRules);
+ }
+ /*
+ 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;
+ }
+ }
+ if (source->reorderCodesLength != target->reorderCodesLength){
+ return FALSE;
+ }
+ for (i = 0; i < source->reorderCodesLength; i++) {
+ if(source->reorderCodes[i] != target->reorderCodes[i]) {
+ 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, ucol_tok_getRulesFromBundle, NULL, &status);
+ ucol_tok_initTokenList(&targetParser, targetRules, targetRulesLen, target->UCA, ucol_tok_getRulesFromBundle, NULL, &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_openFromStringEnumeration(s, status);
+}
+#endif
+
+// Note: KEYWORDS[0] != RESOURCE_NAME - alan
+
+static const char RESOURCE_NAME[] = "collations";
+
+static const char* const 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);
+}
+
+static const UEnumeration defaultKeywordValues = {
+ NULL,
+ NULL,
+ ulist_close_keyword_values_iterator,
+ ulist_count_keyword_values,
+ uenum_unextDefault,
+ ulist_next_keyword_value,
+ ulist_reset_keyword_values_iterator
+};
+
+#include <stdio.h>
+
+U_CAPI UEnumeration* U_EXPORT2
+ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
+ UBool /*commonlyUsed*/, UErrorCode* status) {
+ /* Get the locale base name. */
+ char localeBuffer[ULOC_FULLNAME_CAPACITY] = "";
+ uloc_getBaseName(locale, localeBuffer, sizeof(localeBuffer), status);
+
+ /* Create the 2 lists
+ * -values is the temp location for the keyword values
+ * -results hold the actual list used by the UEnumeration object
+ */
+ UList *values = ulist_createEmptyList(status);
+ UList *results = ulist_createEmptyList(status);
+ UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+ if (U_FAILURE(*status) || en == NULL) {
+ if (en == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ uprv_free(en);
+ }
+ ulist_deleteList(values);
+ ulist_deleteList(results);
+ return NULL;
+ }
+
+ memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
+ en->context = results;
+
+ /* Open the resource bundle for collation with the given locale. */
+ UResourceBundle bundle, collations, collres, defres;
+ ures_initStackObject(&bundle);
+ ures_initStackObject(&collations);
+ ures_initStackObject(&collres);
+ ures_initStackObject(&defres);
+
+ ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
+
+ while (U_SUCCESS(*status)) {
+ ures_getByKey(&bundle, RESOURCE_NAME, &collations, status);
+ ures_resetIterator(&collations);
+ while (U_SUCCESS(*status) && ures_hasNext(&collations)) {
+ ures_getNextResource(&collations, &collres, status);
+ const char *key = ures_getKey(&collres);
+ /* If the key is default, get the string and store it in results list only
+ * if results list is empty.
+ */
+ if (uprv_strcmp(key, "default") == 0) {
+ if (ulist_getListSize(results) == 0) {
+ char *defcoll = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
+ int32_t defcollLength = ULOC_KEYWORDS_CAPACITY;
+
+ ures_getNextResource(&collres, &defres, status);
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+ /* optimize - use the utf-8 string */
+ ures_getUTF8String(&defres, defcoll, &defcollLength, TRUE, status);
+#else
+ {
+ const UChar* defString = ures_getString(&defres, &defcollLength, status);
+ if(U_SUCCESS(*status)) {
+ if(defcollLength+1 > ULOC_KEYWORDS_CAPACITY) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ } else {
+ u_UCharsToChars(defString, defcoll, defcollLength+1);
+ }
+ }
+ }
+#endif
+
+ ulist_addItemBeginList(results, defcoll, TRUE, status);
+ }
+ } else {
+ ulist_addItemEndList(values, key, FALSE, status);
+ }
+ }
+
+ /* If the locale is "" this is root so exit. */
+ if (uprv_strlen(localeBuffer) == 0) {
+ break;
+ }
+ /* Get the parent locale and open a new resource bundle. */
+ uloc_getParent(localeBuffer, localeBuffer, sizeof(localeBuffer), status);
+ ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
+ }
+
+ ures_close(&defres);
+ ures_close(&collres);
+ ures_close(&collations);
+ ures_close(&bundle);
+
+ if (U_SUCCESS(*status)) {
+ char *value = NULL;
+ ulist_resetList(values);
+ while ((value = (char *)ulist_getNext(values)) != NULL) {
+ if (!ulist_containsString(results, value, (int32_t)uprv_strlen(value))) {
+ ulist_addItemEndList(results, value, FALSE, status);
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ }
+ }
+ }
+
+ ulist_deleteList(values);
+
+ if (U_FAILURE(*status)){
+ uenum_close(en);
+ en = NULL;
+ } else {
+ ulist_resetList(results);
+ }
+
+ return en;
+}
+
+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:
+ result = coll->actualLocale;
+ break;
+ case ULOC_VALID_LOCALE:
+ result = coll->validLocale;
+ 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, char *actualLocaleToAdopt)
+{
+ 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;
+ if (coll->actualLocale) {
+ uprv_free(coll->actualLocale);
+ }
+ coll->actualLocale = actualLocaleToAdopt;
+ }
+}
+
+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, ucol_tok_getRulesFromBundle, NULL, 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;
+}
+
+/*
+ * Collation Reordering
+ */
+
+void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ if (parser->reorderCodesLength == 0 || parser->reorderCodes == NULL) {
+ return;
+ }
+
+ coll->reorderCodesLength = 0;
+ if (coll->reorderCodes != NULL && coll->freeReorderCodesOnClose == TRUE) {
+ uprv_free(coll->reorderCodes);
+ }
+
+ if (coll->defaultReorderCodes != NULL && coll->freeDefaultReorderCodesOnClose == TRUE) {
+ uprv_free(coll->defaultReorderCodes);
+ }
+ coll->defaultReorderCodesLength = parser->reorderCodesLength;
+ coll->defaultReorderCodes = (int32_t*) uprv_malloc(coll->defaultReorderCodesLength * sizeof(int32_t));
+ if (coll->defaultReorderCodes == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memcpy(coll->defaultReorderCodes, parser->reorderCodes, coll->defaultReorderCodesLength * sizeof(int32_t));
+ coll->freeDefaultReorderCodesOnClose = TRUE;
+
+ coll->reorderCodesLength = parser->reorderCodesLength;
+ coll->reorderCodes = (int32_t*) uprv_malloc(coll->reorderCodesLength * sizeof(int32_t));
+ if (coll->reorderCodes == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memcpy(coll->reorderCodes, parser->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
+ coll->freeReorderCodesOnClose = TRUE;
+}
+
+/*
+ * Data is stored in the reorder code to lead byte table as:
+ * index count - unsigned short (2 bytes) - number of index entries
+ * data size - unsigned short (2 bytes) - number of unsigned short data elements
+ * index[index count] - array of 2 unsigned shorts (4 bytes each entry)
+ * - reorder code, offset
+ * - index is sorted by reorder code
+ * - if an offset has the high bit set then it is not an offset but a single data entry
+ * once the high bit is stripped off
+ * data[data size] - array of unsigned short (2 bytes each entry)
+ * - the data is an usigned short count followed by count number
+ * of lead bytes stored in an unsigned short
+ */
+U_CFUNC int U_EXPORT2
+ucol_getLeadBytesForReorderCode(const UCollator *uca, int reorderCode, uint16_t* returnLeadBytes, int returnCapacity) {
+ uint16_t reorderCodeIndexLength = *((uint16_t*) ((uint8_t *)uca->image + uca->image->scriptToLeadByte));
+ uint16_t* reorderCodeIndex = (uint16_t*) ((uint8_t *)uca->image + uca->image->scriptToLeadByte + 2 *sizeof(uint16_t));
+
+ // reorder code index is 2 uint16_t's - reorder code + offset
+ for (int i = 0; i < reorderCodeIndexLength; i++) {
+ if (reorderCode == reorderCodeIndex[i*2]) {
+ uint16_t dataOffset = reorderCodeIndex[(i*2) + 1];
+ if ((dataOffset & 0x8000) == 0x8000) {
+ // offset isn't offset but instead is a single data element
+ if (returnCapacity >= 1) {
+ returnLeadBytes[0] = dataOffset & ~0x8000;
+ return 1;
+ }
+ return 0;
+ }
+ uint16_t* dataOffsetBase = (uint16_t*) ((uint8_t *)reorderCodeIndex + reorderCodeIndexLength * (2 * sizeof(uint16_t)));
+ uint16_t leadByteCount = *(dataOffsetBase + dataOffset);
+ leadByteCount = leadByteCount > returnCapacity ? returnCapacity : leadByteCount;
+ uprv_memcpy(returnLeadBytes, dataOffsetBase + dataOffset + 1, leadByteCount * sizeof(uint16_t));
+ return leadByteCount;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Data is stored in the lead byte to reorder code table as:
+ * index count - unsigned short (2 bytes) - number of index entries
+ * data size - unsigned short (2 bytes) - number of unsigned short data elements
+ * index[index count] - array of unsigned short (2 bytes each entry)
+ * - index is sorted by lead byte
+ * - if an index has the high bit set then it is not an index but a single data entry
+ * once the high bit is stripped off
+ * data[data size] - array of unsigned short (2 bytes each entry)
+ * - the data is an usigned short count followed by count number of reorder codes
+ */
+U_CFUNC int U_EXPORT2
+ucol_getReorderCodesForLeadByte(const UCollator *uca, int leadByte, int16_t* returnReorderCodes, int returnCapacity) {
+ uint16_t* leadByteTable = ((uint16_t*) ((uint8_t *)uca->image + uca->image->leadByteToScript));
+ uint16_t leadByteIndexLength = *leadByteTable;
+ if (leadByte >= leadByteIndexLength) {
+ return 0;
+ }
+ uint16_t leadByteIndex = *(leadByteTable + (2 + leadByte));
+
+ if ((leadByteIndex & 0x8000) == 0x8000) {
+ // offset isn't offset but instead is a single data element
+ if (returnCapacity >= 1) {
+ returnReorderCodes[0] = leadByteIndex & ~0x8000;
+ return 1;
+ }
+ return 0;
+ }
+ //uint16_t* dataOffsetBase = leadByteTable + (2 + leadByteIndexLength);
+ uint16_t* reorderCodeData = leadByteTable + (2 + leadByteIndexLength) + leadByteIndex;
+ uint16_t reorderCodeCount = *reorderCodeData > returnCapacity ? returnCapacity : *reorderCodeData;
+ uprv_memcpy(returnReorderCodes, reorderCodeData + 1, reorderCodeCount * sizeof(uint16_t));
+ return reorderCodeCount;
+}
+
+// used to mark ignorable reorder code slots
+static const int32_t UCOL_REORDER_CODE_IGNORE = UCOL_REORDER_CODE_LIMIT + 1;
+
+U_CFUNC void U_EXPORT2
+ucol_buildPermutationTable(UCollator *coll, UErrorCode *status) {
+ uint16_t leadBytesSize = 256;
+ uint16_t leadBytes[256];
+ int32_t internalReorderCodesLength = coll->reorderCodesLength + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST);
+ int32_t* internalReorderCodes;
+
+ // The lowest byte that hasn't been assigned a mapping
+ int toBottom = 0x03;
+ // The highest byte that hasn't been assigned a mapping - don't include the special or trailing
+ int toTop = 0xe4;
+
+ // are we filling from the bottom?
+ bool fromTheBottom = true;
+ int32_t reorderCodesIndex = -1;
+
+ // lead bytes that have alread been assigned to the permutation table
+ bool newLeadByteUsed[256];
+ // permutation table slots that have already been filled
+ bool permutationSlotFilled[256];
+
+ // nothing to do
+ if(U_FAILURE(*status) || coll == NULL) {
+ return;
+ }
+
+ // clear the reordering
+ if (coll->reorderCodes == NULL || coll->reorderCodesLength == 0
+ || (coll->reorderCodesLength == 1 && coll->reorderCodes[0] == UCOL_REORDER_CODE_NONE)) {
+ if (coll->leadBytePermutationTable != NULL) {
+ if (coll->freeLeadBytePermutationTableOnClose) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+ coll->reorderCodesLength = 0;
+ }
+ return;
+ }
+
+ // set reordering to the default reordering
+ if (coll->reorderCodes[0] == UCOL_REORDER_CODE_DEFAULT) {
+ if (coll->reorderCodesLength != 1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (coll->freeReorderCodesOnClose == TRUE) {
+ uprv_free(coll->reorderCodes);
+ }
+ coll->reorderCodes = NULL;
+
+ if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+
+ if (coll->defaultReorderCodesLength == 0) {
+ return;
+ }
+
+ coll->reorderCodes = (int32_t*)uprv_malloc(coll->defaultReorderCodesLength * sizeof(int32_t));
+ coll->freeReorderCodesOnClose = TRUE;
+ if (coll->reorderCodes == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ coll->reorderCodesLength = coll->defaultReorderCodesLength;
+ uprv_memcpy(coll->defaultReorderCodes, coll->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
+ }
+
+ if (coll->leadBytePermutationTable == NULL) {
+ coll->leadBytePermutationTable = (uint8_t*)uprv_malloc(256*sizeof(uint8_t));
+ coll->freeLeadBytePermutationTableOnClose = TRUE;
+ if (coll->leadBytePermutationTable == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ // prefill the reordering codes with the leading entries
+ internalReorderCodes = (int32_t*)uprv_malloc(internalReorderCodesLength * sizeof(int32_t));
+ if (internalReorderCodes == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+ return;
+ }
+
+ for (uint32_t codeIndex = 0; codeIndex < (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST); codeIndex++) {
+ internalReorderCodes[codeIndex] = UCOL_REORDER_CODE_FIRST + codeIndex;
+ }
+ for (int32_t codeIndex = 0; codeIndex < coll->reorderCodesLength; codeIndex++) {
+ uint32_t reorderCodesCode = coll->reorderCodes[codeIndex];
+ internalReorderCodes[codeIndex + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST)] = reorderCodesCode;
+ if (reorderCodesCode >= UCOL_REORDER_CODE_FIRST && reorderCodesCode < UCOL_REORDER_CODE_LIMIT) {
+ internalReorderCodes[reorderCodesCode - UCOL_REORDER_CODE_FIRST] = UCOL_REORDER_CODE_IGNORE;
+ }
+ }
+
+ for (int i = 0; i < 256; i++) {
+ if (i < toBottom || i > toTop) {
+ permutationSlotFilled[i] = true;
+ newLeadByteUsed[i] = true;
+ coll->leadBytePermutationTable[i] = i;
+ } else {
+ permutationSlotFilled[i] = false;
+ newLeadByteUsed[i] = false;
+ coll->leadBytePermutationTable[i] = 0;
+ }
+ }
+
+ /* Start from the front of the list and place each script we encounter at the
+ * earliest possible locatation in the permutation table. If we encounter
+ * UNKNOWN, start processing from the back, and place each script in the last
+ * possible location. At each step, we also need to make sure that any scripts
+ * that need to not be moved are copied to their same location in the final table.
+ */
+ for (int reorderCodesCount = 0; reorderCodesCount < internalReorderCodesLength; reorderCodesCount++) {
+ reorderCodesIndex += fromTheBottom ? 1 : -1;
+ int32_t next = internalReorderCodes[reorderCodesIndex];
+ if (next == UCOL_REORDER_CODE_IGNORE) {
+ continue;
+ }
+ if (next == USCRIPT_UNKNOWN) {
+ if (fromTheBottom == false) {
+ // double turnaround
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+ coll->reorderCodesLength = 0;
+ if (internalReorderCodes != NULL) {
+ uprv_free(internalReorderCodes);
+ }
+ return;
+ }
+ fromTheBottom = false;
+ reorderCodesIndex = internalReorderCodesLength;
+ continue;
+ }
+
+ uint16_t leadByteCount = ucol_getLeadBytesForReorderCode(coll->UCA, next, leadBytes, leadBytesSize);
+ if (fromTheBottom) {
+ for (int leadByteIndex = 0; leadByteIndex < leadByteCount; leadByteIndex++) {
+ // don't place a lead byte twice in the permutation table
+ if (permutationSlotFilled[leadBytes[leadByteIndex]]) {
+ // lead byte already used
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+ coll->reorderCodesLength = 0;
+ if (internalReorderCodes != NULL) {
+ uprv_free(internalReorderCodes);
+ }
+ return;
+ }
+
+ coll->leadBytePermutationTable[leadBytes[leadByteIndex]] = toBottom;
+ newLeadByteUsed[toBottom] = true;
+ permutationSlotFilled[leadBytes[leadByteIndex]] = true;
+ toBottom++;
+ }
+ } else {
+ for (int leadByteIndex = leadByteCount - 1; leadByteIndex >= 0; leadByteIndex--) {
+ // don't place a lead byte twice in the permutation table
+ if (permutationSlotFilled[leadBytes[leadByteIndex]]) {
+ // lead byte already used
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ coll->leadBytePermutationTable = NULL;
+ coll->reorderCodesLength = 0;
+ if (internalReorderCodes != NULL) {
+ uprv_free(internalReorderCodes);
+ }
+ return;
+ }
+
+ coll->leadBytePermutationTable[leadBytes[leadByteIndex]] = toTop;
+ newLeadByteUsed[toTop] = true;
+ permutationSlotFilled[leadBytes[leadByteIndex]] = true;
+ toTop--;
+ }
+ }
+ }
+
+#ifdef REORDER_DEBUG
+ fprintf(stdout, "\n@@@@ Partial Script Reordering Table\n");
+ for (int i = 0; i < 256; i++) {
+ fprintf(stdout, "\t%02x = %02x\n", i, coll->leadBytePermutationTable[i]);
+ }
+ fprintf(stdout, "\n@@@@ Lead Byte Used Table\n");
+ for (int i = 0; i < 256; i++) {
+ fprintf(stdout, "\t%02x = %02x\n", i, newLeadByteUsed[i]);
+ }
+ fprintf(stdout, "\n@@@@ Permutation Slot Filled Table\n");
+ for (int i = 0; i < 256; i++) {
+ fprintf(stdout, "\t%02x = %02x\n", i, permutationSlotFilled[i]);
+ }
+#endif
+
+ /* Copy everything that's left over */
+ int reorderCode = 0;
+ for (int i = 0; i < 256; i++) {
+ if (!permutationSlotFilled[i]) {
+ while (reorderCode < 256 && newLeadByteUsed[reorderCode]) {
+ reorderCode++;
+ }
+ coll->leadBytePermutationTable[i] = reorderCode;
+ permutationSlotFilled[i] = true;
+ newLeadByteUsed[reorderCode] = true;
+ }
+ }
+
+#ifdef REORDER_DEBUG
+ fprintf(stdout, "\n@@@@ Script Reordering Table\n");
+ for (int i = 0; i < 256; i++) {
+ fprintf(stdout, "\t%02x = %02x\n", i, coll->leadBytePermutationTable[i]);
+ }
+#endif
+
+ if (internalReorderCodes != NULL) {
+ uprv_free(internalReorderCodes);
+ }
+
+ // force a regen of the latin one table since it is affected by the script reordering
+ coll->latinOneRegenTable = TRUE;
+ ucol_updateInternalState(coll, status);
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_sit.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_sit.cpp
new file mode 100644
index 00000000000..d5a61c5d37e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_sit.cpp
@@ -0,0 +1,911 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2011, 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 "unicode/udata.h"
+
+#include "utracimp.h"
+#include "ucol_imp.h"
+#include "ucol_tok.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uresimp.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_BCP47,
+ 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
+};
+
+/* 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 = (int32_t)(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 = (int32_t)(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 = (int32_t)(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_getLocaleByType(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*/internalBufferSize, languageArg);
+ elementSize = uloc_getCountry(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, /*capacity*/internalBufferSize, regionArg);
+ elementSize = uloc_getScript(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, /*capacity*/internalBufferSize, scriptArg);
+ elementSize = uloc_getVariant(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, /*capacity*/internalBufferSize, variantArg);
+ elementSize = uloc_getKeywordValue(locBuff, "collation", tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, /*capacity*/internalBufferSize, 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*/internalBufferSize, 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);
+}
+
+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
+ */
+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,
+ ucol_tok_getRulesFromBundle, NULL, 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-4.8.1/i18n/ucol_tok.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.cpp
new file mode 100644
index 00000000000..377f7584592
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.cpp
@@ -0,0 +1,2452 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2011, 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/uscript.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "patternprops.h"
+#include "ucol_bld.h"
+#include "ucol_tok.h"
+#include "ulocimp.h"
+#include "uresimp.h"
+
+// Define this only for debugging.
+// #define DEBUG_FOR_COLL_RULES 1
+
+#ifdef DEBUG_FOR_COLL_RULES
+#include <iostream>
+#endif
+
+U_NAMESPACE_USE
+
+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->source & 0xFF000000)>>24;
+ int32_t inc = ((len - 32) / 32) + 1;
+
+ const UChar *p = (key->source & 0x00FFFFFF) + *(key->rulesToParseHdl);
+ 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->rulesToParseHdl);
+ const UChar *s2 = (p2->source & 0x00FFFFFF) + *(p2->rulesToParseHdl);
+ 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
+
+/*
+ * Debug messages used to pinpoint where a format error occurred.
+ * A better way is to include context-sensitive information in syntaxError() function.
+ *
+ * To turn this debugging on, either uncomment the following line, or define use -DDEBUG_FOR_FORMAT_ERROR
+ * in the compile line.
+ */
+/* #define DEBUG_FOR_FORMAT_ERROR 1 */
+
+#ifdef DEBUG_FOR_FORMAT_ERROR
+#define DBG_FORMAT_ERROR { printf("U_INVALID_FORMAT_ERROR at line %d", __LINE__);}
+#else
+#define DBG_FORMAT_ERROR
+#endif
+
+
+/*
+ * Controls debug messages so that the output can be compared before and after a
+ * big change. Prints the information of every code point that comes out of the
+ * collation parser and its strength into a file. When a big change in format
+ * happens, the files before and after the change should be identical.
+ *
+ * To turn this debugging on, either uncomment the following line, or define use -DDEBUG_FOR_CODE_POINTS
+ * in the compile line.
+ */
+// #define DEBUG_FOR_CODE_POINTS 1
+
+#ifdef DEBUG_FOR_CODE_POINTS
+ FILE* dfcp_fp = NULL;
+#endif
+
+
+/*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 22
+
+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);
+U_STRING_DECL(option_20, "import", 6);
+U_STRING_DECL(option_21, "reorder", 7);
+
+/*
+[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,
+ OPTION_IMPORT,
+ OPTION_SCRIPTREORDER
+} ;
+
+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" */
+ /*20*/ {option_20, 6, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"import" */
+ /*21*/ {option_21, 7, NULL, 0, UCOL_ATTRIBUTE_COUNT} /*"reorder" */
+};
+
+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);
+ U_STRING_INIT(option_20, "import ", 6);
+ U_STRING_INIT(option_21, "reorder", 7);
+ 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 && PatternProps::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(PatternProps::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(PatternProps::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);
+}
+
+/**
+ * Reads an option and matches the option name with the predefined options. (Case-insensitive.)
+ * @param start Pointer to the start UChar.
+ * @param end Pointer to the last valid pointer beyond which the option will not extend.
+ * @param optionArg Address of the pointer at which the options start (after the option name)
+ * @return The index of the option, or -1 if the option is not valid.
+ */
+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(PatternProps::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; /* End of option name; start of the options */
+ while(PatternProps::isWhiteSpace(**optionArg)) { /* eat whitespace */
+ (*optionArg)++;
+ }
+ }
+ break;
+ }
+ i++;
+ }
+ if(i == UTOK_OPTION_COUNT) {
+ i = -1; // didn't find an option
+ }
+ return i;
+}
+
+
+static
+void ucol_tok_parseScriptReorder(UColTokenParser *src, UErrorCode *status) {
+ int32_t codeCount = 0;
+ int32_t codeIndex = 0;
+ char conversion[64];
+ int32_t tokenLength = 0;
+ const UChar* space;
+
+ const UChar* current = src->current;
+ const UChar* end = u_memchr(src->current, 0x005d, src->end - src->current);
+
+ // eat leading whitespace
+ while(current < end && u_isWhitespace(*current)) {
+ current++;
+ }
+
+ while(current < end) {
+ space = u_memchr(current, 0x0020, end - current);
+ space = space == 0 ? end : space;
+ tokenLength = space - current;
+ if (tokenLength < 4) {
+ *status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ codeCount++;
+ current += tokenLength;
+ while(current < end && u_isWhitespace(*current)) { /* eat whitespace */
+ ++current;
+ }
+ }
+
+ if (codeCount == 0) {
+ *status = U_INVALID_FORMAT_ERROR;
+ }
+
+ src->reorderCodesLength = codeCount;
+ src->reorderCodes = (int32_t*)uprv_malloc(codeCount * sizeof(int32_t));
+ current = src->current;
+
+ // eat leading whitespace
+ while(current < end && u_isWhitespace(*current)) {
+ current++;
+ }
+
+ while(current < end) {
+ space = u_memchr(current, 0x0020, end - current);
+ space = space == 0 ? end : space;
+ tokenLength = space - current;
+ if (tokenLength < 4) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ } else {
+ u_UCharsToChars(current, conversion, tokenLength);
+ conversion[tokenLength] = '\0';
+ src->reorderCodes[codeIndex] = ucol_findReorderingEntry(conversion);
+ if (src->reorderCodes[codeIndex] == USCRIPT_INVALID_CODE) {
+ src->reorderCodes[codeIndex] = u_getPropertyValueEnum(UCHAR_SCRIPT, conversion);
+ }
+ if (src->reorderCodes[codeIndex] == USCRIPT_INVALID_CODE) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ codeIndex++;
+ current += tokenLength;
+ while(current < end && u_isWhitespace(*current)) { /* eat whitespace */
+ ++current;
+ }
+ }
+}
+
+// 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;
+ case OPTION_SCRIPTREORDER:
+ ucol_tok_parseScriptReorder(src, status);
+ break;
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+ }
+ src->current = u_memchr(src->current, 0x005d, (int32_t)(src->end-src->current));
+ return result;
+}
+
+
+inline void ucol_tok_addToExtraCurrent(UColTokenParser *src, const UChar *stuff, int32_t len, UErrorCode *status) {
+ if (stuff == NULL || len <= 0) {
+ return;
+ }
+ UnicodeString tempStuff(FALSE, stuff, len);
+ if(src->extraCurrent+len >= src->extraEnd) {
+ /* reallocate */
+ if (stuff >= src->source && stuff <= src->end) {
+ // Copy the "stuff" contents into tempStuff's own buffer.
+ // UnicodeString is copy-on-write.
+ if (len > 0) {
+ tempStuff.setCharAt(0, tempStuff[0]);
+ } else {
+ tempStuff.remove();
+ }
+ }
+ 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;
+ return;
+ }
+ }
+ if(len == 1) {
+ *src->extraCurrent++ = tempStuff[0];
+ } else {
+ u_memcpy(src->extraCurrent, tempStuff.getBuffer(), len);
+ 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;
+ }
+}
+
+/*
+ * This function is called several times when a range is processed. Each time, the next code point
+ * is processed.
+ * The following variables must be set before calling this function:
+ * src->currentRangeCp: The current code point to process.
+ * src->lastRangeCp: The last code point in the range.
+ * Pre-requisite: src->currentRangeCp <= src->lastRangeCp.
+ */
+static const UChar*
+ucol_tok_processNextCodePointInRange(UColTokenParser *src,
+ UErrorCode *status)
+{
+ // Append current code point to source
+ UChar buff[U16_MAX_LENGTH];
+ uint32_t i = 0;
+
+ uint32_t nChars = U16_LENGTH(src->currentRangeCp);
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ src->parsedToken.charsLen = nChars;
+
+ U16_APPEND_UNSAFE(buff, i, src->currentRangeCp);
+ ucol_tok_addToExtraCurrent(src, buff, nChars, status);
+
+ ++src->currentRangeCp;
+ if (src->currentRangeCp > src->lastRangeCp) {
+ src->inRange = FALSE;
+
+ if (src->currentStarredCharIndex > src->lastStarredCharIndex) {
+ src->isStarred = FALSE;
+ }
+ } else {
+ src->previousCp = src->currentRangeCp;
+ }
+ return src->current;
+}
+
+/*
+ * This function is called several times when a starred list is processed. Each time, the next code point
+ * in the list is processed.
+ * The following variables must be set before calling this function:
+ * src->currentStarredCharIndex: Index (in src->source) of the first char of the current code point.
+ * src->lastStarredCharIndex: Index to the last character in the list.
+ * Pre-requisite: src->currentStarredCharIndex <= src->lastStarredCharIndex.
+ */
+static const UChar*
+ucol_tok_processNextTokenInStarredList(UColTokenParser *src)
+{
+ // Extract the characters corresponding to the next code point.
+ UChar32 cp;
+ src->parsedToken.charsOffset = src->currentStarredCharIndex;
+ int32_t prev = src->currentStarredCharIndex;
+ U16_NEXT(src->source, src->currentStarredCharIndex, (uint32_t)(src->end - src->source), cp);
+ src->parsedToken.charsLen = src->currentStarredCharIndex - prev;
+
+ // When we are done parsing the starred string, turn the flag off so that
+ // the normal processing is restored.
+ if (src->currentStarredCharIndex > src->lastStarredCharIndex) {
+ src->isStarred = FALSE;
+ }
+ src->previousCp = cp;
+ return src->current;
+}
+
+/*
+ * Partially parses the next token, keeps the indices in src->parsedToken, and updates the counters.
+ *
+ * This routine parses and separates almost all tokens. The following are the syntax characters recognized.
+ * # : Comment character
+ * & : Reset operator
+ * = : Equality
+ * < : Primary collation
+ * << : Secondary collation
+ * <<< : Tertiary collation
+ * ; : Secondary collation
+ * , : Tertiary collation
+ * / : Expansions
+ * | : Prefix
+ * - : Range
+
+ * ! : Java Thai modifier, ignored
+ * @ : French only
+
+ * [] : Options
+ * '' : Quotes
+ *
+ * Along with operators =, <, <<, <<<, the operator * is supported to indicate a list. For example, &a<*bcdexyz
+ * is equivalent to &a<b<c<d<e<x<y<z. In lists, ranges also can be given, so &a*b-ex-z is equivalent to the above.
+ * This function do not separate the tokens in a list. Instead, &a<*b-ex-z is parsed as three tokens - "&a",
+ * "<*b", "-ex", "-z". The strength (< in this case), whether in a list, whether in a range and the previous
+ * character returned as cached so that the calling program can do further splitting.
+ */
+static const UChar*
+ucol_tok_parseNextTokenInternal(UColTokenParser *src,
+ UBool startOfRules,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ 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);
+ DBG_FORMAT_ERROR
+ 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(!PatternProps::isWhiteSpace(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;
+ if(*(src->current+1) == 0x002A) {/*'*'*/
+ src->current++;
+ src->isStarred = TRUE;
+ }
+ 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;
+ }
+ if(*(src->current+1) == 0x002A) {/*'*'*/
+ src->current++;
+ src->isStarred = TRUE;
+ }
+ 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);
+ DBG_FORMAT_ERROR
+ }
+ } 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);
+ DBG_FORMAT_ERROR
+ }
+ } 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);
+ DBG_FORMAT_ERROR
+ }
+ }
+ } else {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ DBG_FORMAT_ERROR
+ 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);
+ DBG_FORMAT_ERROR
+ 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 (PatternProps::isWhiteSpace(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 0x002D /*-*/: /* A range. */
+ if (newStrength != UCOL_TOK_UNSET) {
+ // While processing the pending token, the isStarred field
+ // is reset, so it needs to be saved for the next
+ // invocation.
+ src->savedIsStarred = src->isStarred;
+ goto EndOfLoop;
+ }
+ src->isStarred = src->savedIsStarred;
+
+ // Ranges are valid only in starred tokens.
+ if (!src->isStarred) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ DBG_FORMAT_ERROR
+ return NULL;
+ }
+ newStrength = src->parsedToken.strength;
+ src->inRange = TRUE;
+ break;
+
+ 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);
+ DBG_FORMAT_ERROR
+ 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);
+ DBG_FORMAT_ERROR
+ 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 || !PatternProps::isWhiteSpace(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;
+ DBG_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;
+}
+
+/*
+ * Parses the next token, keeps the indices in src->parsedToken, and updates the counters.
+ * @see ucol_tok_parseNextTokenInternal() for the description of what operators are supported.
+ *
+ * In addition to what ucol_tok_parseNextTokenInternal() does, this function does the following:
+ * 1) ucol_tok_parseNextTokenInternal() returns a range as a single token. This function separates
+ * it to separate tokens and returns one by one. In order to do that, the necessary states are
+ * cached as member variables of the token parser.
+ * 2) When encountering a range, ucol_tok_parseNextTokenInternal() processes characters up to the
+ * starting character as a single list token (which is separated into individual characters here)
+ * and as another list token starting with the last character in the range. Before expanding it
+ * as a list of tokens, this function expands the range by filling the intermediate characters and
+ * returns them one by one as separate tokens.
+ * Necessary checks are done for invalid combinations.
+ */
+U_CAPI const UChar* U_EXPORT2
+ucol_tok_parseNextToken(UColTokenParser *src,
+ UBool startOfRules,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ const UChar *nextToken;
+
+ if (src->inRange) {
+ // We are not done processing a range. Continue it.
+ return ucol_tok_processNextCodePointInRange(src, status);
+ } else if (src->isStarred) {
+ // We are not done processing a starred token. Continue it.
+ return ucol_tok_processNextTokenInStarredList(src);
+ }
+
+ // Get the next token.
+ nextToken = ucol_tok_parseNextTokenInternal(src, startOfRules, parseError, status);
+
+ if (nextToken == NULL) {
+ return NULL;
+ }
+
+ if (src->inRange) {
+ // A new range has started.
+ // Check whether it is a chain of ranges with more than one hyphen.
+ if (src->lastRangeCp > 0 && src->lastRangeCp == src->previousCp) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,src->parsedToken.charsOffset-1,
+ src->parsedToken.charsOffset+src->parsedToken.charsLen, parseError);
+ DBG_FORMAT_ERROR
+ return NULL;
+ }
+
+ // The current token indicates the second code point of the range.
+ // Process just that, and then proceed with the star.
+ src->currentStarredCharIndex = src->parsedToken.charsOffset;
+ U16_NEXT(src->source, src->currentStarredCharIndex,
+ (uint32_t)(src->end - src->source), src->lastRangeCp);
+ if (src->lastRangeCp <= src->previousCp) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,src->parsedToken.charsOffset-1,
+ src->parsedToken.charsOffset+src->parsedToken.charsLen,parseError);
+ DBG_FORMAT_ERROR
+ return NULL;
+ }
+
+ // Set current range code point to process the range loop
+ src->currentRangeCp = src->previousCp + 1;
+
+ src->lastStarredCharIndex = src->parsedToken.charsOffset + src->parsedToken.charsLen - 1;
+
+ return ucol_tok_processNextCodePointInRange(src, status);
+ } else if (src->isStarred) {
+ // We define two indices m_currentStarredCharIndex_ and m_lastStarredCharIndex_ so that
+ // [m_currentStarredCharIndex_ .. m_lastStarredCharIndex_], both inclusive, need to be
+ // separated into several tokens and returned.
+ src->currentStarredCharIndex = src->parsedToken.charsOffset;
+ src->lastStarredCharIndex = src->parsedToken.charsOffset + src->parsedToken.charsLen - 1;
+
+ return ucol_tok_processNextTokenInStarredList(src);
+ } else {
+ // Set previous codepoint
+ U16_GET(src->source, 0, src->parsedToken.charsOffset, (uint32_t)(src->end - src->source), src->previousCp);
+ }
+ return nextToken;
+}
+
+
+/*
+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, const 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->rulesToParseHdl = &(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);
+ DBG_FORMAT_ERROR
+ uprv_free(sourceToken);
+ 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, status);
+ } else {
+ uprv_init_collIterate(src->UCA, src->source+src->parsedToken.charsOffset /**charsOffset*/, 1, &s, status);
+ }
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ 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.rulesToParseHdl = &(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.rulesToParseHdl = &(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;
+ }
+#ifdef DEBUG_FOR_CODE_POINTS
+ char filename[35];
+ sprintf(filename, "/tmp/debug_for_cp_%09d.txt", getpid());
+ dfcp_fp = fopen(filename, "a");
+ fprintf(stdout, "Output is in the file %s.\n", filename);
+#endif
+
+#ifdef DEBUG_FOR_COLL_RULES
+ std::string s3;
+ UnicodeString(src->source).toUTF8String(s3);
+ std::cout << "src->source = " << s3 << std::endl;
+#endif
+
+ while(src->current < src->end || src->isStarred) {
+ 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;
+ }
+
+#ifdef DEBUG_FOR_CODE_POINTS
+ UChar32 cp;
+ U16_GET(src->source, 0, src->parsedToken.charsOffset, (uint32_t)(src->extraEnd - src->source), cp);
+ fprintf(dfcp_fp, "Code point = %x, Strength = %x\n", cp, src->parsedToken.strength);
+#endif
+ //key = newCharsLen << 24 | charsOffset;
+ UColToken key;
+ key.source = src->parsedToken.charsLen << 24 | src->parsedToken.charsOffset;
+ key.rulesToParseHdl = &(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);
+ DBG_FORMAT_ERROR
+ 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->rulesToParseHdl = &(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);
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ } 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);
+ DBG_FORMAT_ERROR
+ 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.rulesToParseHdl = &(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, status);
+
+ CE = ucol_getNextCE(src->UCA, &s, status);
+ const 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;
+ }
+ }
+ }
+#ifdef DEBUG_FOR_CODE_POINTS
+ fclose(dfcp_fp);
+#endif
+
+
+ if(src->resultLen > 0 && ListList[src->resultLen-1].first == NULL) {
+ src->resultLen--;
+ }
+ return src->resultLen;
+}
+
+const UChar* ucol_tok_getRulesFromBundle(
+ void* /*context*/,
+ const char* locale,
+ const char* type,
+ int32_t* pLength,
+ UErrorCode* status)
+{
+ const UChar* rules = NULL;
+ UResourceBundle* bundle;
+ UResourceBundle* collations;
+ UResourceBundle* collation;
+
+ *pLength = 0;
+
+ bundle = ures_open(U_ICUDATA_COLL, locale, status);
+ if(U_SUCCESS(*status)){
+ collations = ures_getByKey(bundle, "collations", NULL, status);
+ if(U_SUCCESS(*status)){
+ collation = ures_getByKey(collations, type, NULL, status);
+ if(U_SUCCESS(*status)){
+ rules = ures_getStringByKey(collation, "Sequence", pLength, status);
+ if(U_FAILURE(*status)){
+ *pLength = 0;
+ rules = NULL;
+ }
+ ures_close(collation);
+ }
+ ures_close(collations);
+ }
+ }
+
+ ures_close(bundle);
+
+ return rules;
+}
+
+void ucol_tok_initTokenList(
+ UColTokenParser *src,
+ const UChar *rules,
+ uint32_t rulesLength,
+ const UCollator *UCA,
+ GetCollationRulesFunction importFunc,
+ void* context,
+ UErrorCode *status) {
+ U_NAMESPACE_USE
+
+ uint32_t nSize = 0;
+ uint32_t estimatedSize = (2*rulesLength+UCOL_TOK_EXTRA_RULE_SPACE_SIZE);
+
+ bool needToDeallocRules = false;
+
+ 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 = NULL;
+ uint32_t i = 0;
+ while(i < rulesLength) {
+ if(rules[i] == 0x005B) { // '[': start of an option
+ /* Gets the following:
+ optionNumber: The index of the option.
+ setStart: The pointer at which the option arguments start.
+ */
+ optionNumber = ucol_uprv_tok_readOption(rules+i+1, rules+rulesLength, &setStart);
+
+ if(optionNumber == OPTION_OPTIMIZE) { /* copy - parts of UCA to tailoring */
+ // [optimize]
+ 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;
+ }
+ } else if(optionNumber == OPTION_IMPORT){
+ // [import <collation-name>]
+
+ // Find the address of the closing ].
+ UChar* import_end = u_strchr(setStart, 0x005D);
+ int32_t optionEndOffset = (int32_t)(import_end + 1 - rules);
+ // Ignore trailing whitespace.
+ while(PatternProps::isWhiteSpace(*(import_end-1))) {
+ --import_end;
+ }
+
+ int32_t optionLength = (int32_t)(import_end - setStart);
+ char option[50];
+ if(optionLength >= (int32_t)sizeof(option)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ u_UCharsToChars(setStart, option, optionLength);
+ option[optionLength] = 0;
+
+ *status = U_ZERO_ERROR;
+ char locale[50];
+ int32_t templ;
+ uloc_forLanguageTag(option, locale, (int32_t)sizeof(locale), &templ, status);
+ if(U_FAILURE(*status)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ char type[50];
+ if (uloc_getKeywordValue(locale, "collation", type, (int32_t)sizeof(type), status) <= 0 ||
+ U_FAILURE(*status)
+ ) {
+ *status = U_ZERO_ERROR;
+ uprv_strcpy(type, "standard");
+ }
+
+ // TODO: Use public functions when available, see ticket #8134.
+ char *keywords = (char *)locale_getKeywordsStart(locale);
+ if(keywords != NULL) {
+ *keywords = 0;
+ }
+
+ int32_t importRulesLength = 0;
+ const UChar* importRules = importFunc(context, locale, type, &importRulesLength, status);
+
+#ifdef DEBUG_FOR_COLL_RULES
+ std::string s;
+ UnicodeString(importRules).toUTF8String(s);
+ std::cout << "Import rules = " << s << std::endl;
+#endif
+
+ // Add the length of the imported rules to length of the original rules,
+ // and subtract the length of the import option.
+ uint32_t newRulesLength = rulesLength + importRulesLength - (optionEndOffset - i);
+
+ UChar* newRules = (UChar*)uprv_malloc(newRulesLength*sizeof(UChar));
+
+#ifdef DEBUG_FOR_COLL_RULES
+ std::string s1;
+ UnicodeString(rules).toUTF8String(s1);
+ std::cout << "Original rules = " << s1 << std::endl;
+#endif
+
+
+ // Copy the section of the original rules leading up to the import
+ uprv_memcpy(newRules, rules, i*sizeof(UChar));
+ // Copy the imported rules
+ uprv_memcpy(newRules+i, importRules, importRulesLength*sizeof(UChar));
+ // Copy the rest of the original rules (minus the import option itself)
+ uprv_memcpy(newRules+i+importRulesLength,
+ rules+optionEndOffset,
+ (rulesLength-optionEndOffset)*sizeof(UChar));
+
+#ifdef DEBUG_FOR_COLL_RULES
+ std::string s2;
+ UnicodeString(newRules).toUTF8String(s2);
+ std::cout << "Resulting rules = " << s2 << std::endl;
+#endif
+
+ if(needToDeallocRules){
+ // if needToDeallocRules is set, then we allocated rules, so it's safe to cast and free
+ uprv_free((void*)rules);
+ }
+ needToDeallocRules = true;
+ rules = newRules;
+ rulesLength = newRulesLength;
+
+ estimatedSize += importRulesLength*2;
+
+ // First character of the new rules needs to be processed
+ i--;
+ }
+ }
+ //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);
+ }
+ if(needToDeallocRules){
+ // if needToDeallocRules is set, then we allocated rules, so it's safe to cast and free
+ uprv_free((void*)rules);
+ }
+
+
+ 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;
+ src->isStarred = FALSE;
+ src->inRange = FALSE;
+ src->lastRangeCp = 0;
+ src->previousCp = 0;
+
+ 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));
+
+ 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);
+ }
+ if (src->reorderCodes != NULL) {
+ uprv_free(src->reorderCodes);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.h
new file mode 100644
index 00000000000..516534c6577
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_tok.h
@@ -0,0 +1,211 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2011, 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 **rulesToParseHdl;
+ 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. */
+
+ UChar32 previousCp; /* Previous code point. */
+ /* For processing starred lists. */
+ UBool isStarred; /* Are we processing a starred token? */
+ UBool savedIsStarred;
+ uint32_t currentStarredCharIndex; /* Index of the current charrecter in the starred expression. */
+ uint32_t lastStarredCharIndex; /* Index to the last character in the starred expression. */
+
+ /* For processing ranges. */
+ UBool inRange; /* Are we in a range? */
+ UChar32 currentRangeCp; /* Current code point in the range. */
+ UChar32 lastRangeCp; /* The last code point in the range. */
+
+ /* reorder codes for collation reordering */
+ int32_t* reorderCodes;
+ int32_t reorderCodesLength;
+
+} 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,
+ GetCollationRulesFunction importFunc,
+ void* context,
+ 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_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);
+
+const UChar* U_CALLCONV ucol_tok_getRulesFromBundle(
+ void* context,
+ const char* locale,
+ const char* type,
+ int32_t* pLength,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.cpp
new file mode 100644
index 00000000000..87d34fe73a7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.cpp
@@ -0,0 +1,577 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2011, 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 idx) {
+ return getWeightTrail(weight, idx); /* same calculation */
+}
+
+static U_INLINE uint32_t
+setWeightByte(uint32_t weight, int32_t idx, uint32_t byte) {
+ uint32_t mask; /* 0xffffffff except a 00 "hole" for the index-th byte */
+
+ idx*=8;
+ if(idx<32) {
+ mask=((uint32_t)0xffffffff)>>idx;
+ } else {
+ // Do not use uint32_t>>32 because on some platforms that does not shift at all
+ // while we need it to become 0.
+ // PowerPC: 0xffffffff>>32 = 0 (wanted)
+ // x86: 0xffffffff>>32 = 0xffffffff (not wanted)
+ //
+ // ANSI C99 6.5.7 Bitwise shift operators:
+ // "If the value of the right operand is negative
+ // or is greater than or equal to the width of the promoted left operand,
+ // the behavior is undefined."
+ mask=0;
+ }
+ idx=32-idx;
+ mask|=0xffffff00<<idx;
+ return (uint32_t)((weight&mask)|(byte<<idx));
+}
+
+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;
+ }
+}
+
+#if 0 // #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-4.8.1/i18n/ucol_wgt.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.h
new file mode 100644
index 00000000000..b3cb4c9b4f6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucol_wgt.h
@@ -0,0 +1,70 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2008, 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
+
+/* 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-4.8.1/i18n/ucoleitr.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucoleitr.cpp
new file mode 100644
index 00000000000..2d095f23603
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucoleitr.cpp
@@ -0,0 +1,784 @@
+/*
+******************************************************************************
+* Copyright (C) 2001-2011, 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 "unicode/uobject.h"
+#include "ucol_imp.h"
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+#define BUFFER_LENGTH 100
+
+#define DEFAULT_BUFFER_SIZE 16
+#define BUFFER_GROW 8
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define ARRAY_COPY(dst, src, count) uprv_memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0])
+
+#define NEW_ARRAY(type, count) (type *) uprv_malloc((count) * sizeof(type))
+
+#define GROW_ARRAY(array, newSize) uprv_realloc((void *) (array), (newSize) * sizeof (array)[0])
+
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+typedef struct U_NAMESPACE_QUALIFIER collIterate collIterator;
+
+struct RCEI
+{
+ uint32_t ce;
+ int32_t low;
+ int32_t high;
+};
+
+U_NAMESPACE_BEGIN
+
+struct RCEBuffer
+{
+ RCEI defaultBuffer[DEFAULT_BUFFER_SIZE];
+ RCEI *buffer;
+ int32_t bufferIndex;
+ int32_t bufferSize;
+
+ RCEBuffer();
+ ~RCEBuffer();
+
+ UBool empty() const;
+ void put(uint32_t ce, int32_t ixLow, int32_t ixHigh);
+ const RCEI *get();
+};
+
+RCEBuffer::RCEBuffer()
+{
+ buffer = defaultBuffer;
+ bufferIndex = 0;
+ bufferSize = DEFAULT_BUFFER_SIZE;
+}
+
+RCEBuffer::~RCEBuffer()
+{
+ if (buffer != defaultBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+}
+
+UBool RCEBuffer::empty() const
+{
+ return bufferIndex <= 0;
+}
+
+void RCEBuffer::put(uint32_t ce, int32_t ixLow, int32_t ixHigh)
+{
+ if (bufferIndex >= bufferSize) {
+ RCEI *newBuffer = NEW_ARRAY(RCEI, bufferSize + BUFFER_GROW);
+
+ ARRAY_COPY(newBuffer, buffer, bufferSize);
+
+ if (buffer != defaultBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+
+ buffer = newBuffer;
+ bufferSize += BUFFER_GROW;
+ }
+
+ buffer[bufferIndex].ce = ce;
+ buffer[bufferIndex].low = ixLow;
+ buffer[bufferIndex].high = ixHigh;
+
+ bufferIndex += 1;
+}
+
+const RCEI *RCEBuffer::get()
+{
+ if (bufferIndex > 0) {
+ return &buffer[--bufferIndex];
+ }
+
+ return NULL;
+}
+
+struct PCEI
+{
+ uint64_t ce;
+ int32_t low;
+ int32_t high;
+};
+
+struct PCEBuffer
+{
+ PCEI defaultBuffer[DEFAULT_BUFFER_SIZE];
+ PCEI *buffer;
+ int32_t bufferIndex;
+ int32_t bufferSize;
+
+ PCEBuffer();
+ ~PCEBuffer();
+
+ void reset();
+ UBool empty() const;
+ void put(uint64_t ce, int32_t ixLow, int32_t ixHigh);
+ const PCEI *get();
+};
+
+PCEBuffer::PCEBuffer()
+{
+ buffer = defaultBuffer;
+ bufferIndex = 0;
+ bufferSize = DEFAULT_BUFFER_SIZE;
+}
+
+PCEBuffer::~PCEBuffer()
+{
+ if (buffer != defaultBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+}
+
+void PCEBuffer::reset()
+{
+ bufferIndex = 0;
+}
+
+UBool PCEBuffer::empty() const
+{
+ return bufferIndex <= 0;
+}
+
+void PCEBuffer::put(uint64_t ce, int32_t ixLow, int32_t ixHigh)
+{
+ if (bufferIndex >= bufferSize) {
+ PCEI *newBuffer = NEW_ARRAY(PCEI, bufferSize + BUFFER_GROW);
+
+ ARRAY_COPY(newBuffer, buffer, bufferSize);
+
+ if (buffer != defaultBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+
+ buffer = newBuffer;
+ bufferSize += BUFFER_GROW;
+ }
+
+ buffer[bufferIndex].ce = ce;
+ buffer[bufferIndex].low = ixLow;
+ buffer[bufferIndex].high = ixHigh;
+
+ bufferIndex += 1;
+}
+
+const PCEI *PCEBuffer::get()
+{
+ if (bufferIndex > 0) {
+ return &buffer[--bufferIndex];
+ }
+
+ return NULL;
+}
+
+/*
+ * This inherits from UObject so that
+ * it can be allocated by new and the
+ * constructor for PCEBuffer is called.
+ */
+struct UCollationPCE : public UObject
+{
+ PCEBuffer pceBuffer;
+ UCollationStrength strength;
+ UBool toShift;
+ UBool isShifted;
+ uint32_t variableTop;
+
+ UCollationPCE(UCollationElements *elems);
+ ~UCollationPCE();
+
+ void init(const UCollator *coll);
+
+ virtual UClassID getDynamicClassID() const;
+ static UClassID getStaticClassID();
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UCollationPCE)
+
+UCollationPCE::UCollationPCE(UCollationElements *elems)
+{
+ init(elems->iteratordata_.coll);
+}
+
+void UCollationPCE::init(const UCollator *coll)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ strength = ucol_getStrength(coll);
+ toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, &status) == UCOL_SHIFTED;
+ isShifted = FALSE;
+ variableTop = coll->variableTopValue << 16;
+}
+
+UCollationPCE::~UCollationPCE()
+{
+ // nothing to do
+}
+
+
+U_NAMESPACE_END
+
+
+inline uint64_t processCE(UCollationElements *elems, uint32_t ce)
+{
+ uint64_t primary = 0, secondary = 0, tertiary = 0, quaternary = 0;
+
+ // This is clean, but somewhat slow...
+ // We could apply the mask to ce and then
+ // just get all three orders...
+ switch(elems->pce->strength) {
+ default:
+ tertiary = ucol_tertiaryOrder(ce);
+ /* note fall-through */
+
+ case UCOL_SECONDARY:
+ secondary = ucol_secondaryOrder(ce);
+ /* note fall-through */
+
+ case UCOL_PRIMARY:
+ primary = ucol_primaryOrder(ce);
+ }
+
+ // **** This should probably handle continuations too. ****
+ // **** That means that we need 24 bits for the primary ****
+ // **** instead of the 16 that we're currently using. ****
+ // **** So we can lay out the 64 bits as: 24.12.12.16. ****
+ // **** Another complication with continuations is that ****
+ // **** the *second* CE is marked as a continuation, so ****
+ // **** we always have to peek ahead to know how long ****
+ // **** the primary is... ****
+ if ((elems->pce->toShift && elems->pce->variableTop > ce && primary != 0)
+ || (elems->pce->isShifted && primary == 0)) {
+
+ if (primary == 0) {
+ return UCOL_IGNORABLE;
+ }
+
+ if (elems->pce->strength >= UCOL_QUATERNARY) {
+ quaternary = primary;
+ }
+
+ primary = secondary = tertiary = 0;
+ elems->pce->isShifted = TRUE;
+ } else {
+ if (elems->pce->strength >= UCOL_QUATERNARY) {
+ quaternary = 0xFFFF;
+ }
+
+ elems->pce->isShifted = FALSE;
+ }
+
+ return primary << 48 | secondary << 32 | tertiary << 16 | quaternary;
+}
+
+U_CAPI void U_EXPORT2
+uprv_init_pce(const UCollationElements *elems)
+{
+ if (elems->pce != NULL) {
+ elems->pce->init(elems->iteratordata_.coll);
+ }
+}
+
+
+
+/* public methods ---------------------------------------------------- */
+
+U_CAPI UCollationElements* U_EXPORT2
+ucol_openElements(const UCollator *coll,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ UCollationElements *result = new UCollationElements;
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ result->reset_ = TRUE;
+ result->isWritable = FALSE;
+ result->pce = NULL;
+
+ if (text == NULL) {
+ textLength = 0;
+ }
+ uprv_init_collIterate(coll, text, textLength, &result->iteratordata_, status);
+
+ return result;
+}
+
+
+U_CAPI void U_EXPORT2
+ucol_closeElements(UCollationElements *elems)
+{
+ if (elems != NULL) {
+ collIterate *ci = &elems->iteratordata_;
+
+ if (ci->extendCEs) {
+ uprv_free(ci->extendCEs);
+ }
+
+ if (ci->offsetBuffer) {
+ uprv_free(ci->offsetBuffer);
+ }
+
+ if (elems->isWritable && elems->iteratordata_.string != NULL)
+ {
+ uprv_free((UChar *)elems->iteratordata_.string);
+ }
+
+ if (elems->pce != NULL) {
+ delete elems->pce;
+ }
+
+ delete 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 = (ci->flags & UCOL_FORCE_HAN_IMPLICIT) | UCOL_ITER_HASLEN;
+ if (ci->coll->normalizationMode == UCOL_ON) {
+ ci->flags |= UCOL_ITER_NORM;
+ }
+
+ ci->writableBuffer.remove();
+ ci->fcdPosition = NULL;
+
+ //ci->offsetReturn = ci->offsetStore = NULL;
+ ci->offsetRepeatCount = ci->offsetRepeatValue = 0;
+}
+
+U_CAPI void U_EXPORT2
+ucol_forceHanImplicit(UCollationElements *elems, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ if (elems == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ elems->iteratordata_.flags |= UCOL_FORCE_HAN_IMPLICIT;
+}
+
+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 int64_t U_EXPORT2
+ucol_nextProcessed(UCollationElements *elems,
+ int32_t *ixLow,
+ int32_t *ixHigh,
+ UErrorCode *status)
+{
+ const UCollator *coll = elems->iteratordata_.coll;
+ int64_t result = UCOL_IGNORABLE;
+ uint32_t low = 0, high = 0;
+
+ if (U_FAILURE(*status)) {
+ return UCOL_PROCESSED_NULLORDER;
+ }
+
+ if (elems->pce == NULL) {
+ elems->pce = new UCollationPCE(elems);
+ } else {
+ elems->pce->pceBuffer.reset();
+ }
+
+ elems->reset_ = FALSE;
+
+ do {
+ low = ucol_getOffset(elems);
+ uint32_t ce = (uint32_t) ucol_getNextCE(coll, &elems->iteratordata_, status);
+ high = ucol_getOffset(elems);
+
+ if (ce == UCOL_NO_MORE_CES) {
+ result = UCOL_PROCESSED_NULLORDER;
+ break;
+ }
+
+ result = processCE(elems, ce);
+ } while (result == UCOL_IGNORABLE);
+
+ if (ixLow != NULL) {
+ *ixLow = low;
+ }
+
+ if (ixHigh != NULL) {
+ *ixHigh = high;
+ }
+
+ 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 int64_t U_EXPORT2
+ucol_previousProcessed(UCollationElements *elems,
+ int32_t *ixLow,
+ int32_t *ixHigh,
+ UErrorCode *status)
+{
+ const UCollator *coll = elems->iteratordata_.coll;
+ int64_t result = UCOL_IGNORABLE;
+ // int64_t primary = 0, secondary = 0, tertiary = 0, quaternary = 0;
+ // UCollationStrength strength = ucol_getStrength(coll);
+ // UBool toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, status) == UCOL_SHIFTED;
+ // uint32_t variableTop = coll->variableTopValue;
+ int32_t low = 0, high = 0;
+
+ if (U_FAILURE(*status)) {
+ return UCOL_PROCESSED_NULLORDER;
+ }
+
+ 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;
+ }
+
+ if (elems->pce == NULL) {
+ elems->pce = new UCollationPCE(elems);
+ } else {
+ //elems->pce->pceBuffer.reset();
+ }
+
+ elems->reset_ = FALSE;
+
+ while (elems->pce->pceBuffer.empty()) {
+ // buffer raw CEs up to non-ignorable primary
+ RCEBuffer rceb;
+ uint32_t ce;
+
+ // **** do we need to reset rceb, or will it always be empty at this point ****
+ do {
+ high = ucol_getOffset(elems);
+ ce = ucol_getPrevCE(coll, &elems->iteratordata_, status);
+ low = ucol_getOffset(elems);
+
+ if (ce == UCOL_NO_MORE_CES) {
+ if (! rceb.empty()) {
+ break;
+ }
+
+ goto finish;
+ }
+
+ rceb.put(ce, low, high);
+ } while ((ce & UCOL_PRIMARYMASK) == 0);
+
+ // process the raw CEs
+ while (! rceb.empty()) {
+ const RCEI *rcei = rceb.get();
+
+ result = processCE(elems, rcei->ce);
+
+ if (result != UCOL_IGNORABLE) {
+ elems->pce->pceBuffer.put(result, rcei->low, rcei->high);
+ }
+ }
+ }
+
+finish:
+ if (elems->pce->pceBuffer.empty()) {
+ // **** Is -1 the right value for ixLow, ixHigh? ****
+ if (ixLow != NULL) {
+ *ixLow = -1;
+ }
+
+ if (ixHigh != NULL) {
+ *ixHigh = -1
+ ;
+ }
+ return UCOL_PROCESSED_NULLORDER;
+ }
+
+ const PCEI *pcei = elems->pce->pceBuffer.get();
+
+ if (ixLow != NULL) {
+ *ixLow = pcei->low;
+ }
+
+ if (ixHigh != NULL) {
+ *ixHigh = pcei->high;
+ }
+
+ return pcei->ce;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getMaxExpansion(const UCollationElements *elems,
+ int32_t order)
+{
+ uint8_t result;
+
+#if 0
+ UCOL_GETMAXEXPANSION(elems->iteratordata_.coll, (uint32_t)order, result);
+#else
+ const UCollator *coll = elems->iteratordata_.coll;
+ const uint32_t *start;
+ const uint32_t *limit;
+ const uint32_t *mid;
+ uint32_t strengthMask = 0;
+ uint32_t mOrder = (uint32_t) order;
+
+ switch (coll->strength)
+ {
+ default:
+ strengthMask |= UCOL_TERTIARYORDERMASK;
+ /* fall through */
+
+ case UCOL_SECONDARY:
+ strengthMask |= UCOL_SECONDARYORDERMASK;
+ /* fall through */
+
+ case UCOL_PRIMARY:
+ strengthMask |= UCOL_PRIMARYORDERMASK;
+ }
+
+ mOrder &= strengthMask;
+ start = (coll)->endExpansionCE;
+ limit = (coll)->lastEndExpansionCE;
+
+ while (start < limit - 1) {
+ mid = start + ((limit - start) >> 1);
+ if (mOrder <= (*mid & strengthMask)) {
+ limit = mid;
+ } else {
+ start = mid;
+ }
+ }
+
+ // FIXME: with a masked search, there might be more than one hit,
+ // so we need to look forward and backward from the match to find all
+ // of the hits...
+ if ((*start & strengthMask) == mOrder) {
+ result = *((coll)->expansionCESize + (start - (coll)->endExpansionCE));
+ } else if ((*limit & strengthMask) == mOrder) {
+ result = *(coll->expansionCESize + (limit - coll->endExpansionCE));
+ } else if ((mOrder & 0xFFFF) == 0x00C0) {
+ result = 2;
+ } else {
+ result = 1;
+ }
+#endif
+
+ 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((UChar *)elems->iteratordata_.string);
+ }
+
+ if (text == NULL) {
+ textLength = 0;
+ }
+
+ elems->isWritable = FALSE;
+
+ /* free offset buffer to avoid memory leak before initializing. */
+ ucol_freeOffsetBuffer(&(elems->iteratordata_));
+ /* Ensure that previously allocated extendCEs is freed before setting to NULL. */
+ if (elems->iteratordata_.extendCEs != NULL) {
+ uprv_free(elems->iteratordata_.extendCEs);
+ }
+ uprv_init_collIterate(elems->iteratordata_.coll, text, textLength,
+ &elems->iteratordata_, status);
+
+ elems->reset_ = TRUE;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getOffset(const UCollationElements *elems)
+{
+ const collIterate *ci = &(elems->iteratordata_);
+
+ if (ci->offsetRepeatCount > 0 && ci->offsetRepeatValue != 0) {
+ return ci->offsetRepeatValue;
+ }
+
+ if (ci->offsetReturn != NULL) {
+ return *ci->offsetReturn;
+ }
+
+ // 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;
+
+ ci->offsetReturn = NULL;
+ ci->offsetStore = ci->offsetBuffer;
+ ci->offsetRepeatCount = ci->offsetRepeatValue = 0;
+}
+
+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);
+}
+
+
+void ucol_freeOffsetBuffer(collIterate *s) {
+ if (s != NULL && s->offsetBuffer != NULL) {
+ uprv_free(s->offsetBuffer);
+ s->offsetBuffer = NULL;
+ s->offsetBufferSize = 0;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucsdet.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucsdet.cpp
new file mode 100644
index 00000000000..d06dd336428
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/ucurr.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ucurr.cpp
new file mode 100644
index 00000000000..ab3f6e460b4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucurr.cpp
@@ -0,0 +1,2421 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2011, 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 "uhash.h"
+#include "uresimp.h"
+#include "ulist.h"
+#include "ureslocs.h"
+
+// #define UCURR_DEBUG 1
+#ifdef UCURR_DEBUG
+#include "stdio.h"
+#endif
+
+typedef struct IsoCodeEntry {
+ const UChar *isoCode; /* const because it's a reference to a resource bundle string. */
+ UDate from;
+ UDate to;
+} IsoCodeEntry;
+
+//------------------------------------------------------------
+// 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";
+static const char CURRENCYPLURALS[] = "CurrencyPlurals";
+
+// 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};
+
+// ISO codes mapping table
+static UHashtable* gIsoCodes = NULL;
+static UBool gIsoCodesInitialized = FALSE;
+
+static UMTX gIsoCodesLock = NULL;
+
+//------------------------------------------------------------
+// Code
+
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV
+isoCodes_cleanup(void)
+{
+ if (gIsoCodesLock != NULL) {
+ umtx_destroy(&gIsoCodesLock);
+ }
+
+ if (gIsoCodes != NULL) {
+ uhash_close(gIsoCodes);
+ gIsoCodes = NULL;
+ }
+ gIsoCodesInitialized = FALSE;
+
+ return TRUE;
+}
+
+/**
+ * Deleter for OlsonToMetaMappingEntry
+ */
+static void U_CALLCONV
+deleteIsoCodeEntry(void *obj) {
+ IsoCodeEntry *entry = (IsoCodeEntry*)obj;
+ uprv_free(entry);
+}
+
+/**
+ * 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(U_ICUDATA_CURR, 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
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void);
+U_CDECL_END
+
+#if !UCONFIG_NO_SERVICE
+struct CReg;
+
+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_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_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_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);
+ }
+};
+
+// -------------------------------------
+
+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 */
+
+// -------------------------------------
+
+/**
+ * Release all static memory held by currency.
+ */
+/*The declaration here is needed so currency_cleanup(void)
+ * can call this function.
+ */
+static UBool U_CALLCONV
+currency_cache_cleanup(void);
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+ CReg::cleanup();
+#endif
+ /*
+ * There might be some cached currency data or isoCodes data.
+ */
+ currency_cache_cleanup();
+ isoCodes_cleanup();
+
+ return TRUE;
+}
+U_CDECL_END
+
+// -------------------------------------
+
+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) {
+ /* Normalize the currency keyword value to upper case. */
+ T_CString_toUpperCase(id);
+ 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(U_ICUDATA_CURR, 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);
+
+ /* Normalize the keyword value to uppercase */
+ T_CString_toUpperCase(buf);
+
+ const UChar* s = NULL;
+ ec2 = U_ZERO_ERROR;
+ UResourceBundle* rb = ures_open(U_ICUDATA_CURR, 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 const UChar* U_EXPORT2
+ucurr_getPluralName(const UChar* currency,
+ const char* locale,
+ UBool* isChoiceFormat,
+ const char* pluralCount,
+ int32_t* len, // fillin
+ UErrorCode* ec) {
+ // Look up the Currencies resource for the given locale. The
+ // Currencies locale data looks like this:
+ //|en {
+ //| CurrencyPlurals {
+ //| USD{
+ //| one{"US dollar"}
+ //| other{"US dollars"}
+ //| }
+ //| }
+ //|}
+
+ if (U_FAILURE(*ec)) {
+ return 0;
+ }
+
+ // 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(U_ICUDATA_CURR, loc, &ec2);
+
+ rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
+
+ // Fetch resource with multi-level resource inheritance fallback
+ rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
+
+ s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
+ if (U_FAILURE(ec2)) {
+ // fall back to "other"
+ ec2 = U_ZERO_ERROR;
+ s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
+ if (U_FAILURE(ec2)) {
+ ures_close(rb);
+ // fall back to long name in Currencies
+ return ucurr_getName(currency, locale, UCURR_LONG_NAME,
+ isChoiceFormat, len, ec);
+ }
+ }
+ 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;
+ }
+ U_ASSERT(s != NULL);
+ 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;
+}
+
+
+//========================================================================
+// Following are structure and function for parsing currency names
+
+#define NEED_TO_BE_DELETED 0x1
+
+// TODO: a better way to define this?
+#define MAX_CURRENCY_NAME_LEN 100
+
+typedef struct {
+ const char* IsoCode; // key
+ UChar* currencyName; // value
+ int32_t currencyNameLen; // value length
+ int32_t flag; // flags
+} CurrencyNameStruct;
+
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)<(b)) ? (b) : (a))
+#endif
+
+
+// Comparason function used in quick sort.
+static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
+ const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
+ const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
+ for (int32_t i = 0;
+ i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
+ ++i) {
+ if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
+ return -1;
+ }
+ if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
+ return 1;
+ }
+ }
+ if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
+ return -1;
+ } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
+ return 1;
+ }
+ return 0;
+}
+
+
+// Give a locale, return the maximum number of currency names associated with
+// this locale.
+// It gets currency names from resource bundles using fallback.
+// It is the maximum number because in the fallback chain, some of the
+// currency names are duplicated.
+// For example, given locale as "en_US", the currency names get from resource
+// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
+// all currency names in "en_US" and "en".
+static void
+getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
+ U_NAMESPACE_USE
+ *total_currency_name_count = 0;
+ *total_currency_symbol_count = 0;
+ const UChar* s = NULL;
+ char locale[ULOC_FULLNAME_CAPACITY];
+ uprv_strcpy(locale, loc);
+ for (;;) {
+ UErrorCode ec2 = U_ZERO_ERROR;
+ // TODO: ures_openDirect?
+ UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &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) {
+ ChoiceFormat fmt(s, ec2);
+ int32_t fmt_count;
+ fmt.getFormats(fmt_count);
+ *total_currency_symbol_count += fmt_count;
+ } else {
+ ++(*total_currency_symbol_count); // currency symbol
+ }
+
+ ++(*total_currency_symbol_count); // iso code
+ ++(*total_currency_name_count); // long name
+ ures_close(names);
+ }
+
+ // currency plurals
+ UErrorCode ec3 = U_ZERO_ERROR;
+ UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
+ n = ures_getSize(curr_p);
+ for (int32_t i=0; i<n; ++i) {
+ UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
+ *total_currency_name_count += ures_getSize(names);
+ ures_close(names);
+ }
+ ures_close(curr_p);
+ ures_close(curr);
+ ures_close(rb);
+
+ if (!fallback(locale)) {
+ break;
+ }
+ }
+}
+
+// TODO: locale dependent
+static UChar*
+toUpperCase(const UChar* source, int32_t len) {
+ UChar* dest = NULL;
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t destLen = u_strToUpper(dest, 0, source, len, NULL, &ec);
+
+ ec = U_ZERO_ERROR;
+ dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
+ u_strToUpper(dest, destLen, source, len, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ uprv_memcpy(dest, source, sizeof(UChar) * len);
+ }
+ return dest;
+}
+
+
+// Collect all available currency names associated with the give locale
+// (enable fallback chain).
+// Read currenc names defined in resource bundle "Currencies" and
+// "CurrencyPlural", enable fallback chain.
+// return the malloc-ed currency name arrays and the total number of currency
+// names in the array.
+static void
+collectCurrencyNames(const char* locale,
+ CurrencyNameStruct** currencyNames,
+ int32_t* total_currency_name_count,
+ CurrencyNameStruct** currencySymbols,
+ int32_t* total_currency_symbol_count,
+ UErrorCode& ec) {
+ U_NAMESPACE_USE
+ // Look up the Currencies resource for the given locale.
+ 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;
+ }
+
+ // Get maximum currency name count first.
+ getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
+
+ *currencyNames = (CurrencyNameStruct*)uprv_malloc
+ (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
+ *currencySymbols = (CurrencyNameStruct*)uprv_malloc
+ (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
+
+ const UChar* s = NULL; // currency name
+ char* iso = NULL; // currency ISO code
+
+ *total_currency_name_count = 0;
+ *total_currency_symbol_count = 0;
+
+ UErrorCode ec3 = U_ZERO_ERROR;
+ UErrorCode ec4 = U_ZERO_ERROR;
+
+ // Using hash to remove duplicates caused by locale fallback
+ UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
+ UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
+ for (int32_t localeLevel = 0; ; ++localeLevel) {
+ ec2 = U_ZERO_ERROR;
+ // TODO: ures_openDirect
+ UResourceBundle* rb = ures_open(U_ICUDATA_CURR, 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);
+ // TODO: uhash_put wont change key/value?
+ iso = (char*)ures_getKey(names);
+ if (localeLevel == 0) {
+ uhash_put(currencyIsoCodes, iso, iso, &ec3);
+ } else {
+ if (uhash_get(currencyIsoCodes, iso) != NULL) {
+ ures_close(names);
+ continue;
+ } else {
+ uhash_put(currencyIsoCodes, iso, iso, &ec3);
+ }
+ }
+ 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) {
+ ChoiceFormat fmt(s, ec2);
+ int32_t fmt_count;
+ const UnicodeString* formats = fmt.getFormats(fmt_count);
+ for (int i = 0; i < fmt_count; ++i) {
+ // put iso, formats[i]; into array
+ int32_t length = formats[i].length();
+ UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
+ formats[i].extract(0, length, name);
+ (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
+ (*currencySymbols)[*total_currency_symbol_count].currencyName = name;
+ (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
+ (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
+ }
+ } else {
+ // Add currency symbol.
+ (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
+ (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
+ (*currencySymbols)[*total_currency_symbol_count].flag = 0;
+ (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
+ }
+
+ // Add currency long name.
+ s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
+ (*currencyNames)[*total_currency_name_count].IsoCode = iso;
+ UChar* upperName = toUpperCase(s, len);
+ (*currencyNames)[*total_currency_name_count].currencyName = upperName;
+ (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
+ (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
+
+ // put (iso, 3, and iso) in to array
+ // Add currency ISO code.
+ (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
+ (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
+ // Must convert iso[] into Unicode
+ u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
+ (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
+ (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
+
+ ures_close(names);
+ }
+
+ // currency plurals
+ UErrorCode ec3 = U_ZERO_ERROR;
+ UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
+ n = ures_getSize(curr_p);
+ for (int32_t i=0; i<n; ++i) {
+ UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
+ iso = (char*)ures_getKey(names);
+ // Using hash to remove duplicated ISO codes in fallback chain.
+ if (localeLevel == 0) {
+ uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
+ } else {
+ if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
+ ures_close(names);
+ continue;
+ } else {
+ uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
+ }
+ }
+ int32_t num = ures_getSize(names);
+ int32_t len;
+ for (int32_t j = 0; j < num; ++j) {
+ // TODO: remove duplicates between singular name and
+ // currency long name?
+ s = ures_getStringByIndex(names, j, &len, &ec3);
+ (*currencyNames)[*total_currency_name_count].IsoCode = iso;
+ UChar* upperName = toUpperCase(s, len);
+ (*currencyNames)[*total_currency_name_count].currencyName = upperName;
+ (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
+ (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
+ }
+ ures_close(names);
+ }
+ ures_close(curr_p);
+ ures_close(curr);
+ ures_close(rb);
+
+ if (!fallback(loc)) {
+ break;
+ }
+ }
+
+ uhash_close(currencyIsoCodes);
+ uhash_close(currencyPluralIsoCodes);
+
+ // quick sort the struct
+ qsort(*currencyNames, *total_currency_name_count,
+ sizeof(CurrencyNameStruct), currencyNameComparator);
+ qsort(*currencySymbols, *total_currency_symbol_count,
+ sizeof(CurrencyNameStruct), currencyNameComparator);
+
+#ifdef UCURR_DEBUG
+ printf("currency name count: %d\n", *total_currency_name_count);
+ for (int32_t index = 0; index < *total_currency_name_count; ++index) {
+ printf("index: %d\n", index);
+ printf("iso: %s\n", (*currencyNames)[index].IsoCode);
+ printf("currencyName:");
+ for (int32_t i = 0; i < (*currencyNames)[index].currencyNameLen; ++i) {
+ printf("%c", (unsigned char)(*currencyNames)[index].currencyName[i]);
+ }
+ printf("\n");
+ printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
+ }
+ printf("currency symbol count: %d\n", *total_currency_symbol_count);
+ for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
+ printf("index: %d\n", index);
+ printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
+ printf("currencySymbol:");
+ for (int32_t i = 0; i < (*currencySymbols)[index].currencyNameLen; ++i) {
+ printf("%c", (unsigned char)(*currencySymbols)[index].currencyName[i]);
+ }
+ printf("\n");
+ printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
+ }
+#endif
+}
+
+// @param currencyNames: currency names array
+// @param indexInCurrencyNames: the index of the character in currency names
+// array against which the comparison is done
+// @param key: input text char to compare against
+// @param begin(IN/OUT): the begin index of matching range in currency names array
+// @param end(IN/OUT): the end index of matching range in currency names array.
+static int32_t
+binarySearch(const CurrencyNameStruct* currencyNames,
+ int32_t indexInCurrencyNames,
+ const UChar key,
+ int32_t* begin, int32_t* end) {
+#ifdef UCURR_DEBUG
+ printf("key = %x\n", key);
+#endif
+ int32_t first = *begin;
+ int32_t last = *end;
+ while (first <= last) {
+ int32_t mid = (first + last) / 2; // compute mid point.
+ if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
+ first = mid + 1;
+ } else {
+ if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
+ first = mid + 1;
+ }
+ else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
+ last = mid - 1;
+ }
+ else {
+ // Find a match, and looking for ranges
+ // Now do two more binary searches. First, on the left side for
+ // the greatest L such that CurrencyNameStruct[L] < key.
+ int32_t L = *begin;
+ int32_t R = mid;
+
+#ifdef UCURR_DEBUG
+ printf("mid = %d\n", mid);
+#endif
+ while (L < R) {
+ int32_t M = (L + R) / 2;
+#ifdef UCURR_DEBUG
+ printf("L = %d, R = %d, M = %d\n", L, R, M);
+#endif
+ if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
+ L = M + 1;
+ } else {
+ if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
+ L = M + 1;
+ } else {
+#ifdef UCURR_DEBUG
+ U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
+#endif
+ R = M;
+ }
+ }
+ }
+#ifdef UCURR_DEBUG
+ U_ASSERT(L == R);
+#endif
+ *begin = L;
+#ifdef UCURR_DEBUG
+ printf("begin = %d\n", *begin);
+ U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
+#endif
+
+ // Now for the second search, finding the least R such that
+ // key < CurrencyNameStruct[R].
+ L = mid;
+ R = *end;
+ while (L < R) {
+ int32_t M = (L + R) / 2;
+#ifdef UCURR_DEBUG
+ printf("L = %d, R = %d, M = %d\n", L, R, M);
+#endif
+ if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
+ L = M + 1;
+ } else {
+ if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
+ R = M;
+ } else {
+#ifdef UCURR_DEBUG
+ U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
+#endif
+ L = M + 1;
+ }
+ }
+ }
+#ifdef UCURR_DEBUG
+ U_ASSERT(L == R);
+#endif
+ if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
+ *end = R - 1;
+ } else {
+ *end = R;
+ }
+#ifdef UCURR_DEBUG
+ printf("end = %d\n", *end);
+#endif
+
+ // now, found the range. check whether there is exact match
+ if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
+ return *begin; // find range and exact match.
+ }
+ return -1; // find range, but no exact match.
+ }
+ }
+ }
+ *begin = -1;
+ *end = -1;
+ return -1; // failed to find range.
+}
+
+
+// Linear search "text" in "currencyNames".
+// @param begin, end: the begin and end index in currencyNames, within which
+// range should the search be performed.
+// @param textLen: the length of the text to be compared
+// @param maxMatchLen(IN/OUT): passing in the computed max matching length
+// pass out the new max matching length
+// @param maxMatchIndex: the index in currencyName which has the longest
+// match with input text.
+static void
+linearSearch(const CurrencyNameStruct* currencyNames,
+ int32_t begin, int32_t end,
+ const UChar* text, int32_t textLen,
+ int32_t *maxMatchLen, int32_t* maxMatchIndex) {
+ for (int32_t index = begin; index <= end; ++index) {
+ int32_t len = currencyNames[index].currencyNameLen;
+ if (len > *maxMatchLen && len <= textLen &&
+ uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
+ *maxMatchIndex = index;
+ *maxMatchLen = len;
+#ifdef UCURR_DEBUG
+ printf("maxMatchIndex = %d, maxMatchLen = %d\n",
+ *maxMatchIndex, *maxMatchLen);
+#endif
+ }
+ }
+}
+
+#define LINEAR_SEARCH_THRESHOLD 10
+
+// Find longest match between "text" and currency names in "currencyNames".
+// @param total_currency_count: total number of currency names in CurrencyNames.
+// @param textLen: the length of the text to be compared
+// @param maxMatchLen: passing in the computed max matching length
+// pass out the new max matching length
+// @param maxMatchIndex: the index in currencyName which has the longest
+// match with input text.
+static void
+searchCurrencyName(const CurrencyNameStruct* currencyNames,
+ int32_t total_currency_count,
+ const UChar* text, int32_t textLen,
+ int32_t* maxMatchLen, int32_t* maxMatchIndex) {
+ *maxMatchIndex = -1;
+ *maxMatchLen = 0;
+ int32_t matchIndex = -1;
+ int32_t binarySearchBegin = 0;
+ int32_t binarySearchEnd = total_currency_count - 1;
+ // It is a variant of binary search.
+ // For example, given the currency names in currencyNames array are:
+ // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
+ // and the input text is BBEXST
+ // The first round binary search search "B" in the text against
+ // the first char in currency names, and find the first char matching range
+ // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
+ // The 2nd round binary search search the second "B" in the text against
+ // the 2nd char in currency names, and narrow the matching range to
+ // "BB BBEX BBEXYZ" (and the maximum matching "BB").
+ // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
+ // maximum matching).
+ // The 4th round returns the same range (the maximum matching is "BBEX").
+ // The 5th round returns no matching range.
+ for (int32_t index = 0; index < textLen; ++index) {
+ // matchIndex saves the one with exact match till the current point.
+ // [binarySearchBegin, binarySearchEnd] saves the matching range.
+ matchIndex = binarySearch(currencyNames, index,
+ text[index],
+ &binarySearchBegin, &binarySearchEnd);
+ if (binarySearchBegin == -1) { // did not find the range
+ break;
+ }
+ if (matchIndex != -1) {
+ // find an exact match for text from text[0] to text[index]
+ // in currencyNames array.
+ *maxMatchLen = index + 1;
+ *maxMatchIndex = matchIndex;
+ }
+ if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
+ // linear search if within threshold.
+ linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
+ text, textLen,
+ maxMatchLen, maxMatchIndex);
+ break;
+ }
+ }
+ return;
+}
+
+//========================= currency name cache =====================
+typedef struct {
+ char locale[ULOC_FULLNAME_CAPACITY]; //key
+ // currency names, case insensitive
+ CurrencyNameStruct* currencyNames; // value
+ int32_t totalCurrencyNameCount; // currency name count
+ // currency symbols and ISO code, case sensitive
+ CurrencyNameStruct* currencySymbols; // value
+ int32_t totalCurrencySymbolCount; // count
+ // reference count.
+ // reference count is set to 1 when an entry is put to cache.
+ // it increases by 1 before accessing, and decreased by 1 after accessing.
+ // The entry is deleted when ref count is zero, which means
+ // the entry is replaced out of cache and no process is accessing it.
+ int32_t refCount;
+} CurrencyNameCacheEntry;
+
+
+#define CURRENCY_NAME_CACHE_NUM 10
+
+// Reserve 10 cache entries.
+static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
+// Using an index to indicate which entry to be replaced when cache is full.
+// It is a simple round-robin replacement strategy.
+static int8_t currentCacheEntryIndex = 0;
+
+// Cache deletion
+static void
+deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
+ for (int32_t index = 0; index < count; ++index) {
+ if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
+ uprv_free(currencyNames[index].currencyName);
+ }
+ }
+ uprv_free(currencyNames);
+}
+
+
+static void
+deleteCacheEntry(CurrencyNameCacheEntry* entry) {
+ deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
+ deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
+ uprv_free(entry);
+}
+
+
+// Cache clean up
+static UBool U_CALLCONV
+currency_cache_cleanup(void) {
+ for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
+ if (currCache[i]) {
+ deleteCacheEntry(currCache[i]);
+ currCache[i] = 0;
+ }
+ }
+ return TRUE;
+}
+
+
+U_CFUNC void
+uprv_parseCurrency(const char* locale,
+ const U_NAMESPACE_QUALIFIER UnicodeString& text,
+ U_NAMESPACE_QUALIFIER ParsePosition& pos,
+ int8_t type,
+ UChar* result,
+ UErrorCode& ec)
+{
+ U_NAMESPACE_USE
+
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ int32_t total_currency_name_count = 0;
+ CurrencyNameStruct* currencyNames = NULL;
+ int32_t total_currency_symbol_count = 0;
+ CurrencyNameStruct* currencySymbols = NULL;
+ CurrencyNameCacheEntry* cacheEntry = NULL;
+
+ umtx_lock(NULL);
+ // in order to handle racing correctly,
+ // not putting 'search' in a separate function and using UMTX.
+ int8_t found = -1;
+ for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
+ if (currCache[i]!= NULL &&
+ uprv_strcmp(locale, currCache[i]->locale) == 0) {
+ found = i;
+ break;
+ }
+ }
+ if (found != -1) {
+ cacheEntry = currCache[found];
+ currencyNames = cacheEntry->currencyNames;
+ total_currency_name_count = cacheEntry->totalCurrencyNameCount;
+ currencySymbols = cacheEntry->currencySymbols;
+ total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
+ ++(cacheEntry->refCount);
+ }
+ umtx_unlock(NULL);
+ if (found == -1) {
+ collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ umtx_lock(NULL);
+ // check again.
+ int8_t found = -1;
+ for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
+ if (currCache[i]!= NULL &&
+ uprv_strcmp(locale, currCache[i]->locale) == 0) {
+ found = i;
+ break;
+ }
+ }
+ if (found == -1) {
+ // insert new entry to
+ // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
+ // and remove the existing entry
+ // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
+ // from cache.
+ cacheEntry = currCache[currentCacheEntryIndex];
+ if (cacheEntry) {
+ --(cacheEntry->refCount);
+ // delete if the ref count is zero
+ if (cacheEntry->refCount == 0) {
+ deleteCacheEntry(cacheEntry);
+ }
+ }
+ cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
+ currCache[currentCacheEntryIndex] = cacheEntry;
+ uprv_strcpy(cacheEntry->locale, locale);
+ cacheEntry->currencyNames = currencyNames;
+ cacheEntry->totalCurrencyNameCount = total_currency_name_count;
+ cacheEntry->currencySymbols = currencySymbols;
+ cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
+ cacheEntry->refCount = 2; // one for cache, one for reference
+ currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
+ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
+
+ } else {
+ deleteCurrencyNames(currencyNames, total_currency_name_count);
+ deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
+ cacheEntry = currCache[found];
+ currencyNames = cacheEntry->currencyNames;
+ total_currency_name_count = cacheEntry->totalCurrencyNameCount;
+ currencySymbols = cacheEntry->currencySymbols;
+ total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
+ ++(cacheEntry->refCount);
+ }
+ umtx_unlock(NULL);
+ }
+
+ int32_t start = pos.getIndex();
+
+ UChar inputText[MAX_CURRENCY_NAME_LEN];
+ UChar upperText[MAX_CURRENCY_NAME_LEN];
+ int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
+ text.extract(start, textLen, inputText);
+ UErrorCode ec1 = U_ZERO_ERROR;
+ textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, NULL, &ec1);
+
+ int32_t max = 0;
+ int32_t matchIndex = -1;
+ // case in-sensitive comparision against currency names
+ searchCurrencyName(currencyNames, total_currency_name_count,
+ upperText, textLen, &max, &matchIndex);
+
+#ifdef UCURR_DEBUG
+ printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
+#endif
+
+ int32_t maxInSymbol = 0;
+ int32_t matchIndexInSymbol = -1;
+ if (type != UCURR_LONG_NAME) { // not name only
+ // case sensitive comparison against currency symbols and ISO code.
+ searchCurrencyName(currencySymbols, total_currency_symbol_count,
+ inputText, textLen,
+ &maxInSymbol, &matchIndexInSymbol);
+ }
+
+#ifdef UCURR_DEBUG
+ printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
+#endif
+
+ if (max >= maxInSymbol && matchIndex != -1) {
+ u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
+ pos.setIndex(start + max);
+ } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
+ u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
+ pos.setIndex(start + maxInSymbol);
+ }
+
+ // decrease reference count
+ umtx_lock(NULL);
+ --(cacheEntry->refCount);
+ if (cacheEntry->refCount == 0) { // remove
+ deleteCacheEntry(cacheEntry);
+ }
+ umtx_unlock(NULL);
+}
+
+
+/**
+ * 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_CFUNC 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},
+ {"ALK", UCURR_COMMON|UCURR_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},
+ {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ARM", 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},
+ {"BAN", UCURR_COMMON|UCURR_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},
+ {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BGO", UCURR_COMMON|UCURR_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},
+ {"BOL", UCURR_COMMON|UCURR_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},
+ {"BRZ", 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},
+ {"CLE", UCURR_COMMON|UCURR_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},
+ {"CUC", UCURR_COMMON|UCURR_NON_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_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},
+ {"ILR", 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},
+ {"ISJ", UCURR_COMMON|UCURR_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},
+ {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
+ {"KRO", UCURR_COMMON|UCURR_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},
+ {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MDC", 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},
+ {"MKN", UCURR_COMMON|UCURR_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},
+ {"MVP", UCURR_COMMON|UCURR_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_DEPRECATED},
+ {"TMT", 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},
+ {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"UYP", UCURR_COMMON|UCURR_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},
+ {"VNN", UCURR_COMMON|UCURR_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},
+ {"YUR", 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},
+ {"ZWL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ZWD", UCURR_COMMON|UCURR_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 void U_CALLCONV
+ucurr_createCurrencyList(UErrorCode* status){
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ // Look up the CurrencyMap element in the root bundle.
+ UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
+ UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+
+ if (U_SUCCESS(localStatus)) {
+ // process each entry in currency map
+ for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
+ // get the currency resource
+ UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
+ // process each currency
+ if (U_SUCCESS(localStatus)) {
+ for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
+ // get the currency resource
+ UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
+ IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
+ if (entry == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ // get the ISO code
+ int32_t isoLength = 0;
+ UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
+ if (idRes == NULL) {
+ continue;
+ }
+ const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
+
+ // get the from date
+ int32_t fromLength = 0;
+ UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
+ const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
+ int64_t currDate64 = (int64_t)fromArray[0] << 32;
+ currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+ UDate fromDate = (UDate)currDate64;
+ UDate toDate = U_DATE_MAX;
+
+ if (ures_getSize(currencyRes)> 2) {
+ int32_t toLength = 0;
+ UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
+ const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
+
+ currDate64 = (int64_t)toArray[0] << 32;
+ currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+ toDate = (UDate)currDate64;
+
+ ures_close(toRes);
+ }
+
+ ures_close(fromRes);
+ ures_close(idRes);
+ ures_close(currencyRes);
+
+ entry->isoCode = isoCode;
+ entry->from = fromDate;
+ entry->to = toDate;
+
+ uhash_put(gIsoCodes, (UChar *)isoCode, entry, &localStatus);
+ }
+ } else {
+ *status = localStatus;
+ }
+ ures_close(currencyArray);
+ }
+ } else {
+ *status = localStatus;
+ }
+
+ ures_close(currencyMapArray);
+}
+
+static const UEnumeration gEnumCurrencyList = {
+ NULL,
+ NULL,
+ ucurr_closeCurrencyList,
+ ucurr_countCurrencyList,
+ uenum_unextDefault,
+ ucurr_nextCurrencyList,
+ ucurr_resetCurrencyList
+};
+U_CDECL_END
+
+U_CAPI UBool U_EXPORT2
+ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool initialized;
+ UMTX_CHECK(&gIsoCodesLock, gIsoCodesInitialized, initialized);
+
+ if (!initialized) {
+ umtx_lock(&gIsoCodesLock);
+ gIsoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ umtx_unlock(&gIsoCodesLock);
+ return FALSE;
+ }
+ uhash_setValueDeleter(gIsoCodes, deleteIsoCodeEntry);
+
+ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
+
+ ucurr_createCurrencyList(&status);
+ if (U_FAILURE(status)) {
+ umtx_unlock(&gIsoCodesLock);
+ return FALSE;
+ }
+
+ gIsoCodesInitialized = TRUE;
+ umtx_unlock(&gIsoCodesLock);
+ }
+
+ umtx_lock(&gIsoCodesLock);
+ IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
+ umtx_unlock(&gIsoCodesLock);
+
+ if (result == NULL) {
+ return FALSE;
+ } else if (from > to) {
+ *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ } else if ((from > result->to) || (to < result->from)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+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;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucurr_countCurrencies(const char* locale,
+ UDate date,
+ UErrorCode* ec)
+{
+ int32_t currCount = 0;
+ int32_t resLen = 0;
+
+ if (ec != NULL && U_SUCCESS(*ec))
+ {
+ // local variables
+ UErrorCode localStatus = U_ZERO_ERROR;
+ char id[ULOC_FULLNAME_CAPACITY];
+ resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
+ // get country or country_variant in `id'
+ /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
+
+ if (U_FAILURE(*ec))
+ {
+ return 0;
+ }
+
+ // 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(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
+ UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+
+ // Using the id derived from the local, get the currency data
+ UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
+
+ // process each currency to see which one is valid for the given date
+ if (U_SUCCESS(localStatus))
+ {
+ for (int32_t i=0; i<ures_getSize(countryArray); i++)
+ {
+ // get the currency resource
+ UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
+
+ // get the from date
+ int32_t fromLength = 0;
+ UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
+ const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
+
+ int64_t currDate64 = (int64_t)fromArray[0] << 32;
+ currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+ UDate fromDate = (UDate)currDate64;
+
+ if (ures_getSize(currencyRes)> 2)
+ {
+ int32_t toLength = 0;
+ UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
+ const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
+
+ currDate64 = (int64_t)toArray[0] << 32;
+ currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+ UDate toDate = (UDate)currDate64;
+
+ if ((fromDate <= date) && (date < toDate))
+ {
+ currCount++;
+ }
+
+ ures_close(toRes);
+ }
+ else
+ {
+ if (fromDate <= date)
+ {
+ currCount++;
+ }
+ }
+
+ // close open resources
+ ures_close(currencyRes);
+ ures_close(fromRes);
+
+ } // end For loop
+ } // end if (U_SUCCESS(localStatus))
+
+ ures_close(countryArray);
+
+ // Check for errors
+ 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))
+ {
+ // no errors
+ return currCount;
+ }
+
+ }
+
+ // If we got here, either error code is invalid or
+ // some argument passed is no good.
+ return 0;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucurr_forLocaleAndDate(const char* locale,
+ UDate date,
+ int32_t index,
+ UChar* buff,
+ int32_t buffCapacity,
+ UErrorCode* ec)
+{
+ int32_t resLen = 0;
+ int32_t currIndex = 0;
+ const UChar* s = NULL;
+
+ if (ec != NULL && U_SUCCESS(*ec))
+ {
+ // check the arguments passed
+ if ((buff && buffCapacity) || !buffCapacity )
+ {
+ // local variables
+ UErrorCode localStatus = U_ZERO_ERROR;
+ char id[ULOC_FULLNAME_CAPACITY];
+ resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
+
+ // get country or country_variant in `id'
+ /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
+ if (U_FAILURE(*ec))
+ {
+ return 0;
+ }
+
+ // 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(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
+ UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+
+ // Using the id derived from the local, get the currency data
+ UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
+
+ // process each currency to see which one is valid for the given date
+ bool matchFound = false;
+ if (U_SUCCESS(localStatus))
+ {
+ if ((index <= 0) || (index> ures_getSize(countryArray)))
+ {
+ // requested index is out of bounds
+ ures_close(countryArray);
+ return 0;
+ }
+
+ for (int32_t i=0; i<ures_getSize(countryArray); i++)
+ {
+ // get the currency resource
+ UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
+ s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
+
+ // get the from date
+ int32_t fromLength = 0;
+ UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
+ const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
+
+ int64_t currDate64 = (int64_t)fromArray[0] << 32;
+ currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+ UDate fromDate = (UDate)currDate64;
+
+ if (ures_getSize(currencyRes)> 2)
+ {
+ int32_t toLength = 0;
+ UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
+ const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
+
+ currDate64 = (int64_t)toArray[0] << 32;
+ currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+ UDate toDate = (UDate)currDate64;
+
+ if ((fromDate <= date) && (date < toDate))
+ {
+ currIndex++;
+ if (currIndex == index)
+ {
+ matchFound = true;
+ }
+ }
+
+ ures_close(toRes);
+ }
+ else
+ {
+ if (fromDate <= date)
+ {
+ currIndex++;
+ if (currIndex == index)
+ {
+ matchFound = true;
+ }
+ }
+ }
+
+ // close open resources
+ ures_close(currencyRes);
+ ures_close(fromRes);
+
+ // check for loop exit
+ if (matchFound)
+ {
+ break;
+ }
+
+ } // end For loop
+ }
+
+ ures_close(countryArray);
+
+ // Check for errors
+ 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))
+ {
+ // no errors
+ if((buffCapacity> resLen) && matchFound)
+ {
+ // write out the currency value
+ u_strcpy(buff, s);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // return null terminated currency string
+ return u_terminateUChars(buff, buffCapacity, resLen, ec);
+ }
+ else
+ {
+ // illegal argument encountered
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ }
+
+ // If we got here, either error code is invalid or
+ // some argument passed is no good.
+ return resLen;
+}
+
+static const UEnumeration defaultKeywordValues = {
+ NULL,
+ NULL,
+ ulist_close_keyword_values_iterator,
+ ulist_count_keyword_values,
+ uenum_unextDefault,
+ ulist_next_keyword_value,
+ ulist_reset_keyword_values_iterator
+};
+
+U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
+ // Resolve region
+ char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
+ int32_t prefRegionLength = 0;
+ prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
+ if (prefRegionLength == 0) {
+ char loc[ULOC_FULLNAME_CAPACITY] = "";
+ int32_t locLength = 0;
+ locLength = uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
+
+ prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
+ }
+
+ // Read value from supplementalData
+ UList *values = ulist_createEmptyList(status);
+ UList *otherValues = ulist_createEmptyList(status);
+ UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+ if (U_FAILURE(*status) || en == NULL) {
+ if (en == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ uprv_free(en);
+ }
+ ulist_deleteList(values);
+ ulist_deleteList(otherValues);
+ return NULL;
+ }
+ memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
+ en->context = values;
+
+ UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
+ ures_getByKey(bundle, "CurrencyMap", bundle, status);
+ UResourceBundle bundlekey, regbndl, curbndl, to;
+ ures_initStackObject(&bundlekey);
+ ures_initStackObject(&regbndl);
+ ures_initStackObject(&curbndl);
+ ures_initStackObject(&to);
+
+ while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
+ ures_getNextResource(bundle, &bundlekey, status);
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ const char *region = ures_getKey(&bundlekey);
+ UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
+ if (!isPrefRegion && commonlyUsed) {
+ // With commonlyUsed=true, we do not put
+ // currencies for other regions in the
+ // result list.
+ continue;
+ }
+ ures_getByKey(bundle, region, &regbndl, status);
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
+ ures_getNextResource(&regbndl, &curbndl, status);
+ if (ures_getType(&curbndl) != URES_TABLE) {
+ // Currently, an empty ARRAY is mixed in.
+ continue;
+ }
+ char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
+ int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
+ if (curID == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+ ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
+ /* optimize - use the utf-8 string */
+#else
+ {
+ const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
+ if(U_SUCCESS(*status)) {
+ if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ } else {
+ u_UCharsToChars(defString, curID, curIDLength+1);
+ }
+ }
+ }
+#endif
+
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ UBool hasTo = FALSE;
+ ures_getByKey(&curbndl, "to", &to, status);
+ if (U_FAILURE(*status)) {
+ // Do nothing here...
+ *status = U_ZERO_ERROR;
+ } else {
+ hasTo = TRUE;
+ }
+ if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
+ // Currently active currency for the target country
+ ulist_addItemEndList(values, curID, TRUE, status);
+ } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
+ ulist_addItemEndList(otherValues, curID, TRUE, status);
+ } else {
+ uprv_free(curID);
+ }
+ }
+
+ }
+ if (U_SUCCESS(*status)) {
+ if (commonlyUsed) {
+ if (ulist_getListSize(values) == 0) {
+ // This could happen if no valid region is supplied in the input
+ // locale. In this case, we use the CLDR's default.
+ uenum_close(en);
+ en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
+ }
+ } else {
+ // Consolidate the list
+ char *value = NULL;
+ ulist_resetList(otherValues);
+ while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
+ if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
+ char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
+ uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
+ ulist_addItemEndList(values, tmpValue, TRUE, status);
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ }
+ }
+ }
+
+ ulist_resetList((UList *)(en->context));
+ } else {
+ ulist_deleteList(values);
+ uprv_free(en);
+ values = NULL;
+ en = NULL;
+ }
+ ures_close(&to);
+ ures_close(&curbndl);
+ ures_close(&regbndl);
+ ures_close(&bundlekey);
+ ures_close(bundle);
+
+ ulist_deleteList(otherValues);
+
+ return en;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ucurrimp.h b/Build/source/libs/icu/icu-4.8.1/i18n/ucurrimp.h
new file mode 100644
index 00000000000..98871ce4c39
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ucurrimp.h
@@ -0,0 +1,59 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2009, 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_CFUNC 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.
+ * @param type currency type to parse against, LONG_NAME only or not
+ * @return the ISO 4217 code, as a string, of the best match, or
+ * null if there is no match
+ *
+ * @internal
+ */
+U_CFUNC void
+uprv_parseCurrency(const char* locale,
+ const U_NAMESPACE_QUALIFIER UnicodeString& text,
+ U_NAMESPACE_QUALIFIER ParsePosition& pos,
+ int8_t type,
+ UChar* result,
+ UErrorCode& ec);
+
+#endif /* #ifndef _UCURR_IMP_H_ */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/udat.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/udat.cpp
new file mode 100644
index 00000000000..4456a923bed
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/udat.cpp
@@ -0,0 +1,968 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2011, 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"
+#include "reldtfmt.h"
+
+U_NAMESPACE_USE
+
+/**
+ * Verify that fmt is a SimpleDateFormat. Invalid error if not.
+ * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
+ * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
+ */
+static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) {
+ if(U_SUCCESS(*status) &&
+ dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+// This mirrors the correspondence between the
+// SimpleDateFormat::fgPatternIndexToDateFormatField and
+// SimpleDateFormat::fgPatternIndexToCalendarField arrays.
+static UCalendarDateFields gDateFieldMapping[] = {
+ UCAL_ERA, // UDAT_ERA_FIELD = 0
+ UCAL_YEAR, // UDAT_YEAR_FIELD = 1
+ UCAL_MONTH, // UDAT_MONTH_FIELD = 2
+ UCAL_DATE, // UDAT_DATE_FIELD = 3
+ UCAL_HOUR_OF_DAY, // UDAT_HOUR_OF_DAY1_FIELD = 4
+ UCAL_HOUR_OF_DAY, // UDAT_HOUR_OF_DAY0_FIELD = 5
+ UCAL_MINUTE, // UDAT_MINUTE_FIELD = 6
+ UCAL_SECOND, // UDAT_SECOND_FIELD = 7
+ UCAL_MILLISECOND, // UDAT_FRACTIONAL_SECOND_FIELD = 8
+ UCAL_DAY_OF_WEEK, // UDAT_DAY_OF_WEEK_FIELD = 9
+ UCAL_DAY_OF_YEAR, // UDAT_DAY_OF_YEAR_FIELD = 10
+ UCAL_DAY_OF_WEEK_IN_MONTH, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11
+ UCAL_WEEK_OF_YEAR, // UDAT_WEEK_OF_YEAR_FIELD = 12
+ UCAL_WEEK_OF_MONTH, // UDAT_WEEK_OF_MONTH_FIELD = 13
+ UCAL_AM_PM, // UDAT_AM_PM_FIELD = 14
+ UCAL_HOUR, // UDAT_HOUR1_FIELD = 15
+ UCAL_HOUR, // UDAT_HOUR0_FIELD = 16
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_FIELD = 17
+ UCAL_YEAR_WOY, // UDAT_YEAR_WOY_FIELD = 18
+ UCAL_DOW_LOCAL, // UDAT_DOW_LOCAL_FIELD = 19
+ UCAL_EXTENDED_YEAR, // UDAT_EXTENDED_YEAR_FIELD = 20
+ UCAL_JULIAN_DAY, // UDAT_JULIAN_DAY_FIELD = 21
+ UCAL_MILLISECONDS_IN_DAY, // UDAT_MILLISECONDS_IN_DAY_FIELD = 22
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_RFC_FIELD = 23
+ // UCAL_DST_OFFSET also
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_GENERIC_FIELD = 24
+ UCAL_DOW_LOCAL, // UDAT_STANDALONE_DAY_FIELD = 25
+ UCAL_MONTH, // UDAT_STANDALONE_MONTH_FIELD = 26
+ UCAL_MONTH, // UDAT_QUARTER_FIELD = 27
+ UCAL_MONTH, // UDAT_STANDALONE_QUARTER_FIELD = 28
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_SPECIAL_FIELD = 29
+ UCAL_FIELD_COUNT, // UDAT_FIELD_COUNT = 30
+ // UCAL_IS_LEAP_MONTH is not the target of a mapping
+};
+
+U_CAPI UCalendarDateFields U_EXPORT2
+udat_toCalendarDateField(UDateFormatField field) {
+ return gDateFieldMapping[field];
+}
+
+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 = ((DateFormat*)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)
+{
+ verifyIsSimpleDateFormat(fmt, 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)
+{
+ verifyIsSimpleDateFormat(fmt, 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);
+ }
+
+ const DateFormat *df=reinterpret_cast<const DateFormat *>(fmt);
+ const SimpleDateFormat *sdtfmt=dynamic_cast<const SimpleDateFormat *>(df);
+ const RelativeDateFormat *reldtfmt;
+ if (sdtfmt!=NULL) {
+ if(localized)
+ sdtfmt->toLocalizedPattern(res, *status);
+ else
+ sdtfmt->toPattern(res);
+ } else if (!localized && (reldtfmt=dynamic_cast<const RelativeDateFormat *>(df))!=NULL) {
+ reldtfmt->toPattern(res, *status);
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ return res.extract(result, resultLength, *status);
+}
+
+// TODO: should this take an UErrorCode?
+// A: Yes. Of course.
+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;
+
+ verifyIsSimpleDateFormat(format, &status);
+ if(U_FAILURE(status)) {
+ return;
+ }
+
+ 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)
+{
+ const DateFormatSymbols *syms;
+ const SimpleDateFormat* sdtfmt;
+ const RelativeDateFormat* rdtfmt;
+ if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = sdtfmt->getDateFormatSymbols();
+ } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = rdtfmt->getDateFormatSymbols();
+ } else {
+ return -1;
+ }
+ 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;
+}
+
+// TODO: also needs an errorCode.
+U_CAPI int32_t U_EXPORT2
+udat_countSymbols( const UDateFormat *fmt,
+ UDateFormatSymbolType type)
+{
+ const DateFormatSymbols *syms;
+ const SimpleDateFormat* sdtfmt;
+ const RelativeDateFormat* rdtfmt;
+ if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = sdtfmt->getDateFormatSymbols();
+ } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = rdtfmt->getDateFormatSymbols();
+ } else {
+ return 0;
+ }
+ 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)
+{
+ verifyIsSimpleDateFormat(format, 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);
+}
+
+/**
+ * Verify that fmt is a RelativeDateFormat. Invalid error if not.
+ * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
+ * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
+ */
+static void verifyIsRelativeDateFormat(const UDateFormat* fmt, UErrorCode *status) {
+ if(U_SUCCESS(*status) &&
+ dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+
+U_CAPI int32_t U_EXPORT2
+udat_toPatternRelativeDate(const UDateFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ verifyIsRelativeDateFormat(fmt, status);
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString datePattern;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ datePattern.setTo(result, 0, resultLength);
+ }
+ ((RelativeDateFormat*)fmt)->toPatternDate(datePattern, *status);
+ return datePattern.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_toPatternRelativeTime(const UDateFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ verifyIsRelativeDateFormat(fmt, status);
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString timePattern;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ timePattern.setTo(result, 0, resultLength);
+ }
+ ((RelativeDateFormat*)fmt)->toPatternTime(timePattern, *status);
+ return timePattern.extract(result, resultLength, *status);
+}
+
+U_CAPI void U_EXPORT2
+udat_applyPatternRelative(UDateFormat *format,
+ const UChar *datePattern,
+ int32_t datePatternLength,
+ const UChar *timePattern,
+ int32_t timePatternLength,
+ UErrorCode *status)
+{
+ verifyIsRelativeDateFormat(format, status);
+ if(U_FAILURE(*status)) return;
+ const UnicodeString datePat((UBool)(datePatternLength == -1), datePattern, datePatternLength);
+ const UnicodeString timePat((UBool)(timePatternLength == -1), timePattern, timePatternLength);
+ ((RelativeDateFormat*)format)->applyPatterns(datePat, timePat, *status);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/udateintervalformat.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/udateintervalformat.cpp
new file mode 100644
index 00000000000..ef6fc197c75
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/udateintervalformat.cpp
@@ -0,0 +1,106 @@
+/*
+*****************************************************************************************
+* Copyright (C) 2010-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*****************************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udateintervalformat.h"
+#include "unicode/dtitvfmt.h"
+#include "unicode/dtintrv.h"
+#include "unicode/localpointer.h"
+#include "unicode/timezone.h"
+#include "unicode/locid.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_USE
+
+
+U_CAPI UDateIntervalFormat* U_EXPORT2
+udtitvfmt_open(const char* locale,
+ const UChar* skeleton,
+ int32_t skeletonLength,
+ const UChar* tzID,
+ int32_t tzIDLength,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if ((skeleton == NULL ? skeletonLength != 0 : skeletonLength < -1) ||
+ (tzID == NULL ? tzIDLength != 0 : tzIDLength < -1)
+ ) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ UnicodeString skel((UBool)(skeletonLength == -1), skeleton, skeletonLength);
+ LocalPointer<DateIntervalFormat> formatter(
+ DateIntervalFormat::createInstance(skel, Locale(locale), *status));
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if(tzID != 0) {
+ TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
+ if(zone == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ formatter->adoptTimeZone(zone);
+ }
+ return (UDateIntervalFormat*)formatter.orphan();
+}
+
+
+U_CAPI void U_EXPORT2
+udtitvfmt_close(UDateIntervalFormat *formatter)
+{
+ delete (DateIntervalFormat*)formatter;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+udtitvfmt_format(const UDateIntervalFormat* formatter,
+ UDate fromDate,
+ UDate toDate,
+ UChar* result,
+ int32_t resultCapacity,
+ UFieldPosition* position,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return -1;
+ }
+ if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString res;
+ if (result != NULL) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer (copied from udat_format)
+ res.setTo(result, 0, resultCapacity);
+ }
+ FieldPosition fp;
+ if (position != 0) {
+ fp.setField(position->field);
+ }
+
+ DateInterval interval = DateInterval(fromDate,toDate);
+ ((const DateIntervalFormat*)formatter)->format( &interval, res, fp, *status );
+ if (U_FAILURE(*status)) {
+ return -1;
+ }
+ if (position != 0) {
+ position->beginIndex = fp.getBeginIndex();
+ position->endIndex = fp.getEndIndex();
+ }
+
+ return res.extract(result, resultCapacity, *status);
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/udatpg.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/udatpg.cpp
new file mode 100644
index 00000000000..006384f1237
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/udatpg.cpp
@@ -0,0 +1,271 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2009, 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) {
+ return udatpg_getBestPatternWithOptions(dtpg, skeleton, length,
+ UDATPG_MATCH_NO_OPTIONS,
+ bestPattern, capacity, pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+udatpg_getBestPatternWithOptions(UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t length,
+ UDateTimePatternMatchOptions options,
+ 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, options, *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) {
+ return udatpg_replaceFieldTypesWithOptions(dtpg, pattern, patternLength, skeleton, skeletonLength,
+ UDATPG_MATCH_NO_OPTIONS,
+ dest, destCapacity, pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+udatpg_replaceFieldTypesWithOptions(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t patternLength,
+ const UChar *skeleton, int32_t skeletonLength,
+ UDateTimePatternMatchOptions options,
+ 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, options, *pErrorCode);
+ return result.extract(dest, destCapacity, *pErrorCode);
+}
+
+U_DRAFT UEnumeration * U_EXPORT2
+udatpg_openSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
+ return uenum_openFromStringEnumeration(
+ ((DateTimePatternGenerator *)dtpg)->getSkeletons(*pErrorCode),
+ pErrorCode);
+}
+
+U_DRAFT UEnumeration * U_EXPORT2
+udatpg_openBaseSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
+ return uenum_openFromStringEnumeration(
+ ((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-4.8.1/i18n/ulocdata.c b/Build/source/libs/icu/icu-4.8.1/i18n/ulocdata.c
new file mode 100644
index 00000000000..a864c3aa395
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ulocdata.c
@@ -0,0 +1,343 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2011, 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"
+#include "umutex.h"
+#include "uresimp.h"
+#include "ureslocs.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;
+
+ /**
+ * Pointer to the lang resource bundle associated with this locale data object
+ */
+ UResourceBundle *langBundle;
+};
+
+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->langBundle = NULL;
+
+ uld->noSubstitute = FALSE;
+ uld->bundle = ures_open(NULL, localeID, status);
+ uld->langBundle = ures_open(U_ICUDATA_LANG, 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->langBundle);
+ 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",
+ "ExemplarCharactersIndex"};
+ 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_getByKeyWithFallback(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_getByKeyWithFallback(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);
+
+}
+
+U_DRAFT void U_EXPORT2
+ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode *status) {
+ UResourceBundle *rb = NULL;
+ rb = ures_openDirect(NULL, "supplementalData", status);
+ ures_getVersionByKey(rb, "cldrVersion", versionArray, status);
+ ures_close(rb);
+}
+
+U_DRAFT int32_t U_EXPORT2
+ulocdata_getLocaleDisplayPattern(ULocaleData *uld,
+ UChar *result,
+ int32_t resultCapacity,
+ UErrorCode *status) {
+ UResourceBundle *patternBundle;
+ int32_t len = 0;
+ const UChar *pattern = NULL;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return 0;
+
+ patternBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", 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(patternBundle);
+ return 0;
+ }
+
+ pattern = ures_getStringByKey(patternBundle, "pattern", &len, &localStatus);
+ ures_close(patternBundle);
+
+ 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, pattern, resultCapacity);
+ return len;
+}
+
+
+U_DRAFT int32_t U_EXPORT2
+ulocdata_getLocaleSeparator(ULocaleData *uld,
+ UChar *result,
+ int32_t resultCapacity,
+ UErrorCode *status) {
+ UResourceBundle *separatorBundle;
+ int32_t len = 0;
+ const UChar *separator = NULL;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return 0;
+
+ separatorBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", 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(separatorBundle);
+ return 0;
+ }
+
+ separator = ures_getStringByKey(separatorBundle, "separator", &len, &localStatus);
+ ures_close(separatorBundle);
+
+ 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, separator, resultCapacity);
+ return len;
+}
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/umsg.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/umsg.cpp
new file mode 100644
index 00000000000..6c8a09c2648
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/umsg.cpp
@@ -0,0 +1,709 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2011, 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_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);
+ static UBool hasArgTypeConflicts(const MessageFormat& m) {
+ return m.hasArgTypeConflicts;
+ }
+};
+const Formattable::Type*
+MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
+ int32_t& count) {
+ return m.getArgTypeList(count);
+}
+U_NAMESPACE_END
+
+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;
+ }
+
+ int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
+ UnicodeString patString(patternLength == -1, pattern, len);
+
+ MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
+ if(retVal == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
+ *status = U_ARGUMENT_TYPE_MISMATCH;
+ }
+ return (UMessageFormat*)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_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:
+ default:
+ // 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);
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ 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-4.8.1/i18n/umsg_imp.h b/Build/source/libs/icu/icu-4.8.1/i18n/umsg_imp.h
new file mode 100644
index 00000000000..78bbf966bce
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unesctrn.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/unesctrn.cpp
new file mode 100644
index 00000000000..c3d848d06e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unesctrn.cpp
@@ -0,0 +1,290 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2001-2008, 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));
+ // Check for memory allocation error.
+ if (result != NULL) {
+ 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-4.8.1/i18n/unesctrn.h b/Build/source/libs/icu/icu-4.8.1/i18n/unesctrn.h
new file mode 100644
index 00000000000..bfde6fc134f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/uni2name.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uni2name.cpp
new file mode 100644
index 00000000000..5eba79daceb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/uni2name.h b/Build/source/libs/icu/icu-4.8.1/i18n/uni2name.h
new file mode 100644
index 00000000000..aede864564a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/alphaindex.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/alphaindex.h
new file mode 100644
index 00000000000..ad2dd30e330
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/alphaindex.h
@@ -0,0 +1,720 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2011 International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+*/
+
+#ifndef INDEXCHARS_H
+#define INDEXCHARS_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/locid.h"
+
+/**
+ * \file
+ * \brief C++ API: Index Characters
+ */
+
+
+U_CDECL_BEGIN
+
+/**
+ * Constants for Alphabetic Index Label Types.
+ * The form of these enum constants anticipates having a plain C API
+ * for Alphabetic Indexes that will also use them.
+ * @draft ICU 4.8
+ */
+typedef enum UAlphabeticIndexLabelType {
+ /**
+ * Normal Label, typically the starting letter of the names
+ * in the bucket with this label.
+ * @draft ICU 4.8
+ */
+ U_ALPHAINDEX_NORMAL = 0,
+
+ /**
+ * Undeflow Label. The bucket with this label contains names
+ * in scripts that sort before any of the bucket labels in this index.
+ * @draft ICU 4.8
+ */
+ U_ALPHAINDEX_UNDERFLOW = 1,
+
+ /**
+ * Inflow Label. The bucket with this label contains names
+ * in scripts that sort between two of the bucket labels in this index.
+ * Inflow labels are created when an index contains normal labels for
+ * multiple scripts, and skips other scripts that sort between some of the
+ * included scripts.
+ * @draft ICU 4.8
+ */
+ U_ALPHAINDEX_INFLOW = 2,
+
+ /**
+ * Overflow Label. Te bucket with this label contains names in scripts
+ * that sort after all of the bucket labels in this index.
+ * @draft ICU 4.8
+ */
+ U_ALPHAINDEX_OVERFLOW = 3
+ } UAlphabeticIndexLabelType;
+
+
+struct UHashtable;
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+// Forward Declarations
+
+class Collator;
+class RuleBasedCollator;
+class StringEnumeration;
+class UnicodeSet;
+class UVector;
+
+
+
+/**
+ * class AlphabeticIndex supports the creation of a UI index appropriate for a given language, such as:
+ *
+ * <pre>
+ * <b>... A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \\u00C6 \\u00D8 \\u00C5 ...</b>
+ *
+ * <b>A</b>
+ * Addison
+ * Albertson
+ * Azensky
+ * <b>B</b>
+ * Baker
+ * ...
+ * </pre>
+ *
+ * The class can generate a list of labels for use as a UI "index", that is, a list of
+ * clickable characters (or character sequences) that allow the user to see a segment
+ * (bucket) of a larger "target" list. That is, each label corresponds to a bucket in
+ * the target list, where everything in the bucket is greater than or equal to the character
+ * (according to the locale's collation). Strings can be added to the index;
+ * they will be in sorted order in the right bucket.
+ * <p>
+ * The class also supports having buckets for strings before the first (underflow),
+ * after the last (overflow), and between scripts (inflow). For example, if the index
+ * is constructed with labels for Russian and English, Greek characters would fall
+ * into an inflow bucket between the other two scripts.
+ * <p>
+ * The AlphabeticIndex class is not intended for public subclassing.
+ * <p>
+ * <i>Example</i>
+ * <p>
+ * The "show..." methods below are just to illustrate usage.
+ *
+ * <pre>
+ * // Create a simple index. "Item" is assumed to be an application
+ * // defined type that the application's UI and other processing knows about,
+ * // and that has a name.
+ *
+ * UErrorCode status = U_ZERO_ERROR;
+ * AlphabeticIndex index = new AlphabeticIndex(desiredLocale, status);
+ * index->addLabels(additionalLocale, status);
+ * for (Item *item in some source of Items ) {
+ * index->addRecord(item->name(), item, status);
+ * }
+ * ...
+ * // Show index at top. We could skip or gray out empty buckets
+ *
+ * while (index->nextBucket(status)) {
+ * if (showAll || index->getBucketRecordCount() != 0) {
+ * showLabelAtTop(UI, index->getBucketLabel());
+ * }
+ * }
+ * ...
+ * // Show the buckets with their contents, skipping empty buckets
+ *
+ * index->resetBucketIterator(status);
+ * while (index->nextBucket(status)) {
+ * if (index->getBucketRecordCount() != 0) {
+ * showLabelInList(UI, index->getBucketLabel());
+ * while (index->nextRecord(status)) {
+ * showIndexedItem(UI, static_cast<Item *>(index->getRecordData()))
+ * </pre>
+ *
+ * The caller can build different UIs using this class.
+ * For example, an index character could be omitted or grayed-out
+ * if its bucket is empty. Small buckets could also be combined based on size, such as:
+ *
+ * <pre>
+ * <b>... A-F G-N O-Z ...</b>
+ * </pre>
+ *
+ * <p>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>Additional collation parameters can be passed in as part of the locale name.
+ * For example, German plus numeric
+ * sorting would be "de@kn-true".
+ * </ul>
+ *
+ * @draft ICU 4.8 This API might change or be removed in a future release.
+ */
+
+
+class U_I18N_API AlphabeticIndex: public UObject {
+
+ public:
+
+ /**
+ * Construct an AlphabeticIndex object for the specified locale. If the locale's
+ * data does not include index characters, a set of them will be
+ * synthesized based on the locale's exemplar characters. The locale
+ * determines the sorting order for both the index characters and the
+ * user item names appearing under each Index character.
+ *
+ * @param locale the desired locale.
+ * @param status Error code, will be set with the reason if the construction
+ * of the AlphabeticIndex object fails.
+ * @draft ICU 4.8
+ */
+ AlphabeticIndex(const Locale &locale, UErrorCode &status);
+
+
+
+ /**
+ * Add Labels to this Index. The labels are additions to those
+ * that are already in the index; they do not replace the existing
+ * ones.
+ * @param additions The additional characters to add to the index, such as A-Z.
+ * @param status Error code, will be set with the reason if the
+ * operation fails.
+ * @return this, for chaining
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &addLabels(const UnicodeSet &additions, UErrorCode &status);
+
+ /**
+ * Add the index characters from a Locale to the index. The labels
+ * are added to those that are already in the index; they do not replace the
+ * existing index characters. The collation order for this index is not
+ * changed; it remains that of the locale that was originally specified
+ * when creating this Index.
+ *
+ * @param locale The locale whose index characters are to be added.
+ * @param status Error code, will be set with the reason if the
+ * operation fails.
+ * @return this, for chaining
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &addLabels(const Locale &locale, UErrorCode &status);
+
+ /**
+ * Destructor
+ * @draft ICU 4.8
+ */
+ virtual ~AlphabeticIndex();
+
+
+ /**
+ * Get the Collator that establishes the ordering of the items in this index.
+ * Ownership of the collator remains with the AlphabeticIndex instance.
+ *
+ * The returned collator is a reference to the internal collator used by this
+ * index. It may be safely used to compare the names of items or to get
+ * sort keys for names. However if any settings need to be changed,
+ * or other non-const methods called, a cloned copy must be made first.
+ *
+ * @return The collator
+ * @draft ICU 4.8
+ */
+ virtual const RuleBasedCollator &getCollator() const;
+
+
+ /**
+ * Get the default label used for abbreviated buckets <i>between</i> other index characters.
+ * For example, consider the labels when Latin and Greek are used:
+ * X Y Z ... &#x0391; &#x0392; &#x0393;.
+ *
+ * @return inflow label
+ * @draft ICU 4.8
+ */
+ virtual const UnicodeString &getInflowLabel() const;
+
+ /**
+ * Set the default label used for abbreviated buckets <i>between</i> other index characters.
+ * An inflow label will be automatically inserted if two otherwise-adjacent label characters
+ * are from different scripts, e.g. Latin and Cyrillic, and a third script, e.g. Greek,
+ * sorts between the two. The default inflow character is an ellipsis (...)
+ *
+ * @param inflowLabel the new Inflow label.
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return this
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &setInflowLabel(const UnicodeString &inflowLabel, UErrorCode &status);
+
+
+
+ /**
+ * Get the special label used for items that sort after the last normal label,
+ * and that would not otherwise have an appropriate label.
+ *
+ * @return the overflow label
+ * @draft ICU 4.8
+ */
+ virtual const UnicodeString &getOverflowLabel() const;
+
+
+ /**
+ * Set the label used for items that sort after the last normal label,
+ * and that would not otherwise have an appropriate label.
+ *
+ * @param overflowLabel the new overflow label.
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return this
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &setOverflowLabel(const UnicodeString &overflowLabel, UErrorCode &status);
+
+ /**
+ * Get the special label used for items that sort before the first normal label,
+ * and that would not otherwise have an appropriate label.
+ *
+ * @return underflow label
+ * @draft ICU 4.8
+ */
+ virtual const UnicodeString &getUnderflowLabel() const;
+
+ /**
+ * Set the label used for items that sort before the first normal label,
+ * and that would not otherwise have an appropriate label.
+ *
+ * @param underflowLabel the new underflow label.
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return this
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &setUnderflowLabel(const UnicodeString &underflowLabel, UErrorCode &status);
+
+
+ /**
+ * Get the limit on the number of labels permitted in the index.
+ * The number does not include over, under and inflow labels.
+ *
+ * @return maxLabelCount maximum number of labels.
+ * @draft ICU 4.8
+ */
+ virtual int32_t getMaxLabelCount() const;
+
+ /**
+ * Set a limit on the number of labels permitted in the index.
+ * The number does not include over, under and inflow labels.
+ * Currently, if the number is exceeded, then every
+ * nth item is removed to bring the count down.
+ * A more sophisticated mechanism may be available in the future.
+ *
+ * @param maxLabelCount the maximum number of labels.
+ * @param status error code
+ * @return This, for chaining
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &setMaxLabelCount(int32_t maxLabelCount, UErrorCode &status);
+
+
+ /**
+ * Get the Unicode character (or tailored string) that defines an overflow bucket;
+ * that is anything greater than or equal to that string should go in that bucket,
+ * instead of with the last character. Normally that is the first character of the script
+ * after lowerLimit. Thus in X Y Z ... <i>Devanagari-ka</i>, the overflow character for Z
+ * would be the <i>Greek-alpha</i>.
+ *
+ * @param lowerLimit The character below the overflow (or inflow) bucket
+ * @param status error code
+ * @return string that defines top of the overflow buck for lowerLimit, or an empty string if there is none
+ * @internal
+ */
+ virtual const UnicodeString &getOverflowComparisonString(const UnicodeString &lowerLimit,
+ UErrorCode &status);
+
+
+ /**
+ * Add a record to the index. Each record will be associated with an index Bucket
+ * based on the record's name. The list of records for each bucket will be sorted
+ * based on the collation ordering of the names in the index's locale.
+ * Records with duplicate names are permitted; they will be kept in the order
+ * that they were added.
+ *
+ * @param name The display name for the Record. The Record will be placed in
+ * a bucket based on this name.
+ * @param data An optional pointer to user data associated with this
+ * item. When iterating the contents of a bucket, both the
+ * data pointer the name will be available for each Record.
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return This, for chaining.
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &addRecord(const UnicodeString &name, const void *data, UErrorCode &status);
+
+ /**
+ * Remove all Records from the Index. The set of Buckets, which define the headings under
+ * which records are classified, is not altered.
+ *
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return This, for chaining.
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &clearRecords(UErrorCode &status);
+
+
+ /** Get the number of labels in this index.
+ * Note: may trigger lazy index construction.
+ *
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return The number of labels in this index, including any under, over or
+ * in-flow labels.
+ * @draft ICU 4.8
+ */
+ virtual int32_t getBucketCount(UErrorCode &status);
+
+
+ /** Get the total number of Records in this index, that is, the number
+ * of <name, data> pairs added.
+ *
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return The number of records in this index, that is, the total number
+ * of (name, data) items added with addRecord().
+ * @draft ICU 4.8
+ */
+ virtual int32_t getRecordCount(UErrorCode &status);
+
+
+
+ /**
+ * Given the name of a record, return the zero-based index of the Bucket
+ * in which the item should appear. The name need not be in the index.
+ * A Record will not be added to the index by this function.
+ * Bucket numbers are zero-based, in Bucket iteration order.
+ *
+ * @param itemName The name whose bucket position in the index is to be determined.
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return The bucket number for this name.
+ * @draft ICU 4.8
+ *
+ */
+ virtual int32_t getBucketIndex(const UnicodeString &itemName, UErrorCode &status);
+
+
+ /**
+ * Get the zero based index of the current Bucket from an iteration
+ * over the Buckets of this index. Return -1 if no iteration is in process.
+ * @return the index of the current Bucket
+ * @draft ICU 4.8
+ */
+ virtual int32_t getBucketIndex() const;
+
+
+ /**
+ * Advance the iteration over the Buckets of this index. Return FALSE if
+ * there are no more Buckets.
+ *
+ * @param status Error code, will be set with the reason if the operation fails.
+ * U_ENUM_OUT_OF_SYNC_ERROR will be reported if the index is modified while
+ * an enumeration of its contents are in process.
+ *
+ * @return TRUE if success, FALSE if at end of iteration
+ * @draft ICU 4.8
+ */
+ virtual UBool nextBucket(UErrorCode &status);
+
+ /**
+ * Return the name of the Label of the current bucket from an iteration over the buckets.
+ * If the iteration is before the first Bucket (nextBucket() has not been called),
+ * or after the last, return an empty string.
+ *
+ * @return the bucket label.
+ * @draft ICU 4.8
+ */
+ virtual const UnicodeString &getBucketLabel() const;
+
+ /**
+ * Return the type of the label for the current Bucket (selected by the
+ * iteration over Buckets.)
+ *
+ * @return the label type.
+ * @draft ICU 4.8
+ */
+ virtual UAlphabeticIndexLabelType getBucketLabelType() const;
+
+ /**
+ * Get the number of <name, data> Records in the current Bucket.
+ * If the current bucket iteration position is before the first label or after the
+ * last, return 0.
+ *
+ * @return the number of Records.
+ * @draft ICU 4.8
+ */
+ virtual int32_t getBucketRecordCount() const;
+
+
+ /**
+ * Reset the Bucket iteration for this index. The next call to nextBucket()
+ * will restart the iteration at the first label.
+ *
+ * @param status Error code, will be set with the reason if the operation fails.
+ * @return this, for chaining.
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &resetBucketIterator(UErrorCode &status);
+
+ /**
+ * Advance to the next record in the current Bucket.
+ * When nextBucket() is called, Record iteration is reset to just before the
+ * first Record in the new Bucket.
+ *
+ * @param status Error code, will be set with the reason if the operation fails.
+ * U_ENUM_OUT_OF_SYNC_ERROR will be reported if the index is modified while
+ * an enumeration of its contents are in process.
+ * @return TRUE if successful, FALSE when the iteration advances past the last item.
+ * @draft ICU 4.8
+ */
+ virtual UBool nextRecord(UErrorCode &status);
+
+ /**
+ * Get the name of the current Record.
+ * Return an empty string if the Record iteration position is before first
+ * or after the last.
+ *
+ * @return The name of the current index item.
+ * @draft ICU 4.8
+ */
+ virtual const UnicodeString &getRecordName() const;
+
+
+ /**
+ * Return the data pointer of the Record currently being iterated over.
+ * Return NULL if the current iteration position before the first item in this Bucket,
+ * or after the last.
+ *
+ * @return The current Record's data pointer.
+ * @draft ICU 4.8
+ */
+ virtual const void *getRecordData() const;
+
+
+ /**
+ * Reset the Record iterator position to before the first Record in the current Bucket.
+ *
+ * @return This, for chaining.
+ * @draft ICU 4.8
+ */
+ virtual AlphabeticIndex &resetRecordIterator();
+
+private:
+ // No ICU "poor man's RTTI" for this class nor its subclasses.
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * No Copy constructor.
+ * @internal
+ */
+ AlphabeticIndex(const AlphabeticIndex &other);
+
+ /**
+ * No assignment.
+ */
+ AlphabeticIndex &operator =(const AlphabeticIndex & /*other*/) { return *this;};
+
+ /**
+ * No Equality operators.
+ * @internal
+ */
+ virtual UBool operator==(const AlphabeticIndex& other) const;
+
+ /**
+ * Inequality operator.
+ * @internal
+ */
+ virtual UBool operator!=(const AlphabeticIndex& other) const;
+
+ // Common initialization, for use from all constructors.
+ void init(UErrorCode &status);
+
+ // Initialize & destruct static constants used by this class.
+ static void staticInit(UErrorCode &status);
+
+ // Pinyin stuff. If the input name is Chinese, add the Pinyin prefix to the dest string.
+ void hackName(UnicodeString &dest, const UnicodeString &name, const Collator *coll);
+ void initPinyinBounds(const Collator *coll, UErrorCode &status);
+
+ public:
+ /**
+ * Delete all shared (static) data associated with an AlphabeticIndex.
+ * Internal function, not intended for direct use.
+ * @internal.
+ */
+ static void staticCleanup();
+ private:
+
+ // Add index characters from the specified locale to the dest set.
+ // Does not remove any previous contents from dest.
+ static void getIndexExemplars(UnicodeSet &dest, const Locale &locale, UErrorCode &status);
+
+ UVector *firstStringsInScript(UErrorCode &status);
+
+ static UnicodeString separated(const UnicodeString &item);
+
+ static UnicodeSet *getScriptSet(UnicodeSet &dest, const UnicodeString &codePoint, UErrorCode &status);
+
+ void buildIndex(UErrorCode &status);
+ void buildBucketList(UErrorCode &status);
+ void bucketRecords(UErrorCode &status);
+
+
+ public:
+
+ // The following internal items are declared public only to allow access from
+ // implementation code written in plain C. They are not intended for
+ // public use.
+
+ /**
+ * A record, or item, in the index.
+ * @internal
+ */
+ struct Record: public UMemory {
+ AlphabeticIndex *alphaIndex_;
+ const UnicodeString name_;
+ UnicodeString sortingName_; // Usually the same as name_; different for Pinyin.
+ const void *data_;
+ int32_t serialNumber_; // Defines sorting order for names that compare equal.
+ Record(AlphabeticIndex *alphaIndex, const UnicodeString &name, const void *data);
+ ~Record();
+ };
+
+ /**
+ * Holds all user records before they are distributed into buckets.
+ * Type of contents is (Record *)
+ * @internal
+ */
+ UVector *inputRecords_;
+
+ /**
+ * A Bucket holds an index label and references to everything belonging to that label.
+ * For implementation use only. Declared public because pure C implementation code needs access.
+ * @internal
+ */
+ struct Bucket: public UMemory {
+ UnicodeString label_;
+ UnicodeString lowerBoundary_;
+ UAlphabeticIndexLabelType labelType_;
+ UVector *records_; // Records are owned by inputRecords_ vector.
+
+ Bucket(const UnicodeString &label, // Parameter strings are copied.
+ const UnicodeString &lowerBoundary,
+ UAlphabeticIndexLabelType type, UErrorCode &status);
+ ~Bucket();
+ };
+
+ public:
+
+ /**
+ * Language Types. For internal ICU use only.
+ * @internal
+ */
+ enum ELangType {
+ /** @internal */
+ kNormal,
+ /** @internal */
+ kSimplified,
+ /** @internal */
+ kTraditional
+ };
+
+ /**
+ * Get the Language Type for this Index. Based on the locale.
+ * @internal
+ */
+ static ELangType langTypeFromLocale(const Locale &loc);
+
+
+ private:
+
+ // Holds the contents of this index, buckets of user items.
+ // UVector elements are of type (Bucket *)
+ UVector *bucketList_;
+
+ int32_t labelsIterIndex_; // Index of next item to return.
+ int32_t itemsIterIndex_;
+ Bucket *currentBucket_; // While an iteration of the index in underway,
+ // point to the bucket for the current label.
+ // NULL when no iteration underway.
+
+ UBool indexBuildRequired_; // Caller has made changes to the index that
+ // require rebuilding & bucketing before the
+ // contents can be iterated.
+
+ int32_t maxLabelCount_; // Limit on # of labels permitted in the index.
+
+ UHashtable *alreadyIn_; // Key=UnicodeString, value=UnicodeSet
+
+ UnicodeSet *initialLabels_; // Initial (unprocessed) set of Labels. Union
+ // of those explicitly set by the user plus
+ // those from locales. Raw values, before
+ // crunching into bucket labels.
+
+ UVector *labels_; // List of Labels, after processing, sorting.
+ // Contents are (UnicodeString *)
+
+ UnicodeSet *noDistinctSorting_; // As the set of labels is built, strings may
+ // be discarded from the exemplars. This contains
+ // some of the discards, and is
+ // intended for debugging.
+
+ UnicodeSet *notAlphabetic_; // As the set of labels is built, strings may
+ // be discarded from the exemplars. This contains
+ // some of the discards, and is
+ // intended for debugging.
+
+
+ UVector *firstScriptCharacters_; // The first character from each script,
+ // in collation order.
+
+ Locale locale_;
+ Collator *collator_;
+ Collator *collatorPrimaryOnly_;
+
+ UnicodeString inflowLabel_;
+ UnicodeString overflowLabel_;
+ UnicodeString underflowLabel_;
+ UnicodeString overflowComparisonString_;
+
+ ELangType langType_; // The language type, simplified Chinese, Traditional Chinese,
+ // or not Chinese (Normal). Part of the Pinyin support
+
+ typedef const UChar PinyinLookup[24][3];
+ static PinyinLookup HACK_PINYIN_LOOKUP_SHORT;
+ static PinyinLookup HACK_PINYIN_LOOKUP_LONG;
+
+ // These will be lazily set to the short or long tables based on which
+ // Chinese collation has been configured into the ICU library.
+ static PinyinLookup *HACK_PINYIN_LOOKUP;
+ static const UChar *PINYIN_LOWER_BOUNDS;
+
+
+
+ int32_t recordCounter_; // Counts Records created. For minting record serial numbers.
+
+// Constants. Lazily initialized the first time an AlphabeticIndex object is created.
+
+ static UnicodeSet *ALPHABETIC;
+ static UnicodeSet *CORE_LATIN;
+ static UnicodeSet *ETHIOPIC;
+ static UnicodeSet *HANGUL;
+ static UnicodeSet *IGNORE_SCRIPTS;
+ static UnicodeSet *TO_TRY;
+ static UnicodeSet *UNIHAN;
+ static const UnicodeString *EMPTY_STRING;
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/basictz.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/basictz.h
new file mode 100644
index 00000000000..f3d34a663c7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/basictz.h
@@ -0,0 +1,210 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, 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.
+ * @stable ICU 3.8
+ */
+class U_I18N_API BasicTimeZone: public TimeZone {
+public:
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ BasicTimeZone();
+
+ /**
+ * Construct a timezone with a given ID.
+ * @param id a system time zone ID
+ * @stable ICU 3.8
+ */
+ BasicTimeZone(const UnicodeString &id);
+
+ /**
+ * Copy constructor.
+ * @param source the object to be copied.
+ * @stable 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-4.8.1/i18n/unicode/bms.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/bms.h
new file mode 100644
index 00000000000..516e6aa2280
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/bms.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 1996-2010, International Business Machines Corporation and Others.
+ * All rights reserved.
+ */
+
+/**
+ * \file
+ * \brief C API: Boyer-Moore StringSearch prototype.
+ * \internal
+ */
+
+#ifndef _BMS_H
+#define _BMS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/ucol.h"
+
+/**
+ * A <code>UCD</code> object holds the Collator-specific data needed to
+ * compute the length of the shortest string that can
+ * generate a partcular list of CEs.
+ *
+ * <code>UCD</code> objects are quite expensive to compute. Because
+ * of this, they are cached. When you call <code>ucd_open</code> it
+ * returns a reference counted cached object. When you call <code>ucd_close</code>
+ * the reference count on the object is decremented but the object is not deleted.
+ *
+ * If you do not need to reuse any unreferenced objects in the cache, you can call
+ * <code>ucd_flushCCache</code>. If you no longer need any <code>UCD</code>
+ * objects, you can call <code>ucd_freeCache</code>
+ */
+typedef void UCD;
+
+/**
+ * Open a <code>UCD</code> object.
+ *
+ * @param coll - the collator
+ * @param status - will be set if any errors occur.
+ *
+ * @return the <code>UCD</code> object. You must call
+ * <code>ucd_close</code> when you are done using the object.
+ *
+ * Note: if on return status is set to an error, the only safe
+ * thing to do with the returned object is to call <code>ucd_close</code>.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI UCD * U_EXPORT2
+ucd_open(UCollator *coll, UErrorCode *status);
+
+/**
+ * Release a <code>UCD</code> object.
+ *
+ * @param ucd - the object
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI void U_EXPORT2
+ucd_close(UCD *ucd);
+
+/**
+ * Get the <code>UCollator</code> object used to create a <code>UCD</code> object.
+ * The <code>UCollator</code> object returned may not be the exact
+ * object that was used to create this object, but it will have the
+ * same behavior.
+ *
+ * @param ucd - the <code>UCD</code> object
+ *
+ * @return the <code>UCollator</code> used to create the given
+ * <code>UCD</code> object.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI UCollator * U_EXPORT2
+ucd_getCollator(UCD *ucd);
+
+/**
+ * <code>UCD</code> objects are expensive to compute, and so
+ * may be cached. This routine will free the cached objects and delete
+ * the cache.
+ *
+ * WARNING: Don't call this until you are have called <code>close</code>
+ * for each <code>UCD</code> object that you have used. also,
+ * DO NOT call this if another thread may be calling <code>ucd_flushCache</code>
+ * at the same time.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI void U_EXPORT2
+ucd_freeCache();
+
+/**
+ * <code>UCD</code> objects are expensive to compute, and so
+ * may be cached. This routine will remove any unused <code>UCD</code>
+ * objects from the cache.
+ *
+ * @internal 4.0.1 technology preview
+ */
+U_CAPI void U_EXPORT2
+ucd_flushCache();
+
+/**
+ * BMS
+ *
+ * This object holds the information needed to do a Collation sensitive Boyer-Moore search. It encapulates
+ * the pattern, the "bad character" and "good suffix" tables, the Collator-based data needed to compute them,
+ * and a reference to the text being searched.
+ *
+ * To do a search, you first need to get a <code>UCD</code> object by calling <code>ucd_open</code>.
+ * Then you construct a <code>BMS</code> object from the <code>UCD</code> object, the pattern
+ * string and the target string. Then you call the <code>search</code> method. Here's a code sample:
+ *
+ * <pre>
+ * void boyerMooreExample(UCollator *collator, UChar *pattern, int32_t patternLen, UChar *target, int32_t targetLength)
+ * {
+ * UErrorCode status = U_ZERO_ERROR;
+ * int32_t offset = 0, start = -1, end = -1;
+ * UCD *ucd = NULL);
+ * BMS *bms = NULL;
+ *
+ * ucd = ucd_open(collator, &status);
+ * if (U_FAILURE(status)) {
+ * // could not create a UCD object
+ * return;
+ * }
+ *
+ * BMS *bms = bms_open(ucd, pattern, patternLength, target, targetlength, &status);
+ * if (U_FAILURE(status)) {
+ * // could not create a BMS object
+ * ucd_close(ucd);
+ * return;
+ * }
+ *
+ *
+ * // Find all matches
+ * while (bms_search(bms, offset, &start, &end)) {
+ * // process the match between start and end
+ * ...
+ *
+ * // advance past the match
+ * offset = end;
+ * }
+ *
+ * // at this point, if offset == 0, there were no matches
+ * if (offset == 0) {
+ * // handle the case of no matches
+ * }
+ *
+ * bms_close(bms);
+ * ucd_close(ucd);
+ *
+ * // UCD objects are cached, so the call to
+ * // ucd_close doesn't delete the object.
+ * // Call this if you don't need the object any more.
+ * ucd_flushCache();
+ * }
+ * </pre>
+ *
+ * NOTE: This is a technology preview. The final version of this API may not bear any resenblence to this API.
+ *
+ * Knows linitations:
+ * 1) Backwards searching has not been implemented.
+ *
+ * 2) For Han and Hangul characters, this code ignores any Collation tailorings. In general,
+ * this isn't a problem, but in Korean locals, at strength 1, Hangul characters are tailored
+ * to be equal to Han characters with the same pronounciation. Because this code ignroes
+ * tailorings, searching for a Hangul character will not find a Han character and visa-versa.
+ *
+ * 3) In some cases, searching for a pattern that needs to be normalized and ends
+ * in a discontiguous contraction may fail. The only known cases of this are with
+ * the Tibetan script. For example searching for the pattern
+ * "\u0F7F\u0F80\u0F81\u0F82\u0F83\u0F84\u0F85" will fail. (This case is artificial. We've
+ * been unable to find a pratical, real-world example of this failure.)
+ *
+ * NOTE: This is a technology preview. The final version of this API may not bear any resenblence to this API.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+struct BMS;
+typedef struct BMS BMS; /**< @see BMS */
+
+/**
+ * Construct a <code>MBS</code> object.
+ *
+ * @param ucd - A <code>UCD</code> object holding the Collator-sensitive data
+ * @param pattern - the string for which to search
+ * @param patternLength - the length of the string for which to search
+ * @param target - the string in which to search
+ * @param targetLength - the length of the string in which to search
+ * @param status - will be set if any errors occur.
+ *
+ * @return the <code>BMS</code> object.
+ *
+ * Note: if on return status is set to an error, the only safe
+ * thing to do with the returned object is to call
+ * <code>bms_close</code>.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI BMS * U_EXPORT2
+bms_open(UCD *ucd,
+ const UChar *pattern, int32_t patternLength,
+ const UChar *target, int32_t targetLength,
+ UErrorCode *status);
+
+/**
+ * Close a <code>BMS</code> object and release all the
+ * storage associated with it.
+ *
+ * @param bms - the <code>BMS</code> object to close.
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI void U_EXPORT2
+bms_close(BMS *bms);
+
+/**
+ * Test the pattern to see if it generates any CEs.
+ *
+ * @param bms - the <code>BMS</code> object
+ * @return <code>TRUE</code> if the pattern string did not generate any CEs
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI UBool U_EXPORT2
+bms_empty(BMS *bms);
+
+/**
+ * Get the <code>UCD</code> object used to create
+ * a given <code>BMS</code> object.
+ *
+ * @param bms - the <code>BMS</code> object
+ *
+ * @return - the <code>UCD</code> object used to create
+ * the given <code>BMS</code> object.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI UCD * U_EXPORT2
+bms_getData(BMS *bms);
+
+/**
+ * Search for the pattern string in the target string.
+ *
+ * @param bms - the <code>BMS</code> object
+ * @param offset - the offset in the target string at which to begin the search
+ * @param start - will be set to the starting offset of the match, or -1 if there's no match
+ * @param end - will be set to the ending offset of the match, or -1 if there's no match
+ *
+ * @return <code>TRUE</code> if the match succeeds, <code>FALSE</code> otherwise.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI UBool U_EXPORT2
+bms_search(BMS *bms, int32_t offset, int32_t *start, int32_t *end);
+
+/**
+ * Set the target string for the match.
+ *
+ * @param bms - the <code>BMS</code> object
+ * @param target - the new target string
+ * @param targetLength - the length of the new target string
+ * @param status - will be set if any errors occur.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+U_CAPI void U_EXPORT2
+bms_setTargetString(BMS *bms, const UChar *target, int32_t targetLength, UErrorCode *status);
+
+#endif
+
+#endif /* _BMS_H */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/bmsearch.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/bmsearch.h
new file mode 100644
index 00000000000..b5973e579c0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/bmsearch.h
@@ -0,0 +1,226 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines *
+ * Corporation and others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+/**
+ * \file
+ * \brief C++ API: Boyer-Moore StringSearch technology preview
+ * \internal ICU 4.0.1 technology preview
+ */
+
+#ifndef B_M_SEARCH_H
+#define B_M_SEARCH_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/ucol.h"
+
+#include "unicode/colldata.h"
+
+U_NAMESPACE_BEGIN
+
+class BadCharacterTable;
+class GoodSuffixTable;
+class Target;
+
+/**
+ * BoyerMooreSearch
+ *
+ * This object holds the information needed to do a Collation sensitive Boyer-Moore search. It encapulates
+ * the pattern, the "bad character" and "good suffix" tables, the Collator-based data needed to compute them,
+ * and a reference to the text being searched.
+ *
+ * To do a search, you fist need to get a <code>CollData</code> object by calling <code>CollData::open</code>.
+ * Then you construct a <code>BoyerMooreSearch</code> object from the <code>CollData</code> object, the pattern
+ * string and the target string. Then you call the <code>search</code> method. Here's a code sample:
+ *
+ * <pre>
+ * void boyerMooreExample(UCollator *collator, UnicodeString *pattern, UnicodeString *target)
+ * {
+ * UErrorCode status = U_ZERO_ERROR;
+ * CollData *collData = CollData::open(collator, status);
+ *
+ * if (U_FAILURE(status)) {
+ * // could not create a CollData object
+ * return;
+ * }
+ *
+ * BoyerMooreSearch *search = new BoyerMooreSearch(collData, *patternString, target, status);
+ *
+ * if (U_FAILURE(status)) {
+ * // could not create a BoyerMooreSearch object
+ * CollData::close(collData);
+ * return;
+ * }
+ *
+ * int32_t offset = 0, start = -1, end = -1;
+ *
+ * // Find all matches
+ * while (search->search(offset, start, end)) {
+ * // process the match between start and end
+ * ...
+ * // advance past the match
+ * offset = end;
+ * }
+ *
+ * // at this point, if offset == 0, there were no matches
+ * if (offset == 0) {
+ * // handle the case of no matches
+ * }
+ *
+ * delete search;
+ * CollData::close(collData);
+ *
+ * // CollData objects are cached, so the call to
+ * // CollData::close doesn't delete the object.
+ * // Call this if you don't need the object any more.
+ * CollData::flushCollDataCache();
+ * }
+ * </pre>
+ *
+ * NOTE: This is a technology preview. The final version of this API may not bear any resenblence to this API.
+ *
+ * Knows linitations:
+ * 1) Backwards searching has not been implemented.
+ *
+ * 2) For Han and Hangul characters, this code ignores any Collation tailorings. In general,
+ * this isn't a problem, but in Korean locals, at strength 1, Hangul characters are tailored
+ * to be equal to Han characters with the same pronounciation. Because this code ignroes
+ * tailorings, searching for a Hangul character will not find a Han character and visa-versa.
+ *
+ * 3) In some cases, searching for a pattern that needs to be normalized and ends
+ * in a discontiguous contraction may fail. The only known cases of this are with
+ * the Tibetan script. For example searching for the pattern
+ * "\u0F7F\u0F80\u0F81\u0F82\u0F83\u0F84\u0F85" will fail. (This case is artificial. We've
+ * been unable to find a pratical, real-world example of this failure.)
+ *
+ * @internal ICU 4.0.1 technology preview
+ *
+ * @see CollData
+ */
+class U_I18N_API BoyerMooreSearch : public UObject
+{
+public:
+ /**
+ * Construct a <code>BoyerMooreSearch</code> object.
+ *
+ * @param theData - A <code>CollData</code> object holding the Collator-sensitive data
+ * @param patternString - the string for which to search
+ * @param targetString - the string in which to search or <code>NULL</code> if youu will
+ * set it later by calling <code>setTargetString</code>.
+ * @param status - will be set if any errors occur.
+ *
+ * Note: if on return, status is set to an error code,
+ * the only safe thing to do with this object is to call
+ * the destructor.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ BoyerMooreSearch(CollData *theData, const UnicodeString &patternString, const UnicodeString *targetString, UErrorCode &status);
+
+ /**
+ * The desstructor
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ ~BoyerMooreSearch();
+
+ /**
+ * Test the pattern to see if it generates any CEs.
+ *
+ * @return <code>TRUE</code> if the pattern string did not generate any CEs
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ UBool empty();
+
+ /**
+ * Search for the pattern string in the target string.
+ *
+ * @param offset - the offset in the target string at which to begin the search
+ * @param start - will be set to the starting offset of the match, or -1 if there's no match
+ * @param end - will be set to the ending offset of the match, or -1 if there's no match
+ *
+ * @return <code>TRUE</code> if the match succeeds, <code>FALSE</code> otherwise.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ UBool search(int32_t offset, int32_t &start, int32_t &end);
+
+ /**
+ * Set the target string for the match.
+ *
+ * @param targetString - the new target string
+ * @param status - will be set if any errors occur.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ void setTargetString(const UnicodeString *targetString, UErrorCode &status);
+
+ // **** no longer need these? ****
+ /**
+ * Return the <code>CollData</code> object used for searching
+ *
+ * @return the <code>CollData</code> object used for searching
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ CollData *getData();
+
+ /**
+ * Return the CEs generated by the pattern string.
+ *
+ * @return a <code>CEList</code> object holding the CEs generated by the pattern string.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ CEList *getPatternCEs();
+
+ /**
+ * Return the <code>BadCharacterTable</code> object computed for the pattern string.
+ *
+ * @return the <code>BadCharacterTable</code> object.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ BadCharacterTable *getBadCharacterTable();
+
+ /**
+ * Return the <code>GoodSuffixTable</code> object computed for the pattern string.
+ *
+ * @return the <code>GoodSuffixTable</code> object computed for the pattern string.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ GoodSuffixTable *getGoodSuffixTable();
+
+ /**
+ * UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ virtual UClassID getDynamicClassID() const;
+ /**
+ * UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ static UClassID getStaticClassID();
+
+private:
+ CollData *data;
+ CEList *patCEs;
+ BadCharacterTable *badCharacterTable;
+ GoodSuffixTable *goodSuffixTable;
+ UnicodeString pattern;
+ Target *target;
+};
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_COLLATION
+#endif // #ifndef B_M_SEARCH_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/calendar.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/calendar.h
new file mode 100644
index 00000000000..f3b3fa6f3c6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/calendar.h
@@ -0,0 +1,2258 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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 may be defined on other platforms. To avoid any potential problems undefined it here.
+ */
+#ifdef ERA
+#undef ERA
+#endif
+ 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
+
+ EXTENDED_YEAR,
+ JULIAN_DAY,
+ MILLISECONDS_IN_DAY,
+ IS_LEAP_MONTH,
+
+ 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);
+
+
+ /**
+ * Given a key and a locale, returns an array of string values in a preferred
+ * order that would make a difference. These are all and only those values where
+ * the open (creation) of the service with the locale formed from the input locale
+ * plus input keyword and that value has different behavior than creation with the
+ * input locale alone.
+ * @param key one of the keys supported by this service. For now, only
+ * "calendar" is supported.
+ * @param locale the locale
+ * @param commonlyUsed if set to true it will return only commonly used values
+ * with the given locale in preferred order. Otherwise,
+ * it will return all the available values for the locale.
+ * @param status ICU Error Code
+ * @return a string enumeration over keyword values for the given key and the locale.
+ * @stable ICU 4.2
+ */
+ static StringEnumeration* U_EXPORT2 getKeywordValuesForLocale(const char* key,
+ const Locale& locale, UBool commonlyUsed, UErrorCode& status);
+
+ /**
+ * 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.
+ */
+ virtual 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.
+ */
+ virtual 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;
+
+ /**
+ * Returns whether the given day of the week is a weekday, a
+ * weekend day, or a day that transitions from one to the other,
+ * in this calendar system. If a transition occurs at midnight,
+ * then the days before and after the transition will have the
+ * type UCAL_WEEKDAY or UCAL_WEEKEND. If a transition occurs at a time
+ * other than midnight, then the day of the transition will have
+ * the type UCAL_WEEKEND_ONSET or UCAL_WEEKEND_CEASE. In this case, the
+ * method getWeekendTransition() will return the point of
+ * transition.
+ * @param dayOfWeek The day of the week whose type is desired (UCAL_SUNDAY..UCAL_SATURDAY).
+ * @param status The error code for the operation.
+ * @return The UCalendarWeekdayType for the day of the week.
+ * @stable ICU 4.4
+ */
+ virtual UCalendarWeekdayType getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const;
+
+ /**
+ * Returns the time during the day at which the weekend begins or ends in
+ * this calendar system. If getDayOfWeekType() rerturns UCAL_WEEKEND_ONSET
+ * for the specified dayOfWeek, return the time at which the weekend begins.
+ * If getDayOfWeekType() returns UCAL_WEEKEND_CEASE for the specified dayOfWeek,
+ * return the time at which the weekend ends. If getDayOfWeekType() returns
+ * some other UCalendarWeekdayType for the specified dayOfWeek, is it an error condition
+ * (U_ILLEGAL_ARGUMENT_ERROR).
+ * @param dayOfWeek The day of the week for which the weekend transition time is
+ * desired (UCAL_SUNDAY..UCAL_SATURDAY).
+ * @param status The error code for the operation.
+ * @return The milliseconds after midnight at which the weekend begins or ends.
+ * @stable ICU 4.4
+ */
+ virtual int32_t getWeekendTransition(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) const;
+
+ /**
+ * Returns TRUE if the given UDate is in the weekend in
+ * this calendar system.
+ * @param date The UDate in question.
+ * @param status The error code for the operation.
+ * @return TRUE if the given UDate is in the weekend in
+ * this calendar system, FALSE otherwise.
+ * @stable ICU 4.4
+ */
+ virtual UBool isWeekend(UDate date, UErrorCode &status) const;
+
+ /**
+ * Returns TRUE if this Calendar's current date-time is in the weekend in
+ * this calendar system.
+ * @return TRUE if this Calendar's current date-time is in the weekend in
+ * this calendar system, FALSE otherwise.
+ * @stable ICU 4.4
+ */
+ virtual UBool isWeekend(void) const;
+
+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.
+ * @param eyear The extended year
+ * @internal
+ */
+ virtual int32_t getDefaultMonthInYear(int32_t eyear) ;
+
+
+ /**
+ * 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.
+ * @param eyear the extended year
+ * @param month the month in the year
+ * @internal
+ */
+ virtual int32_t getDefaultDayInMonth(int32_t eyear, 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;
+
+ /**
+ * Recalculates the time stamp array (fStamp).
+ * Resets fNextStamp to lowest next stamp value.
+ */
+ void recalculateStamp();
+
+ /**
+ * 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;
+ UCalendarDaysOfWeek fWeekendOnset;
+ int32_t fWeekendOnsetMillis;
+ UCalendarDaysOfWeek fWeekendCease;
+ int32_t fWeekendCeaseMillis;
+
+ /**
+ * 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 setWeekData(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);
+
+protected:
+
+ /**
+ * 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.
+ */
+ void computeGregorianFields(int32_t julianDay, UErrorCode &ec);
+
+private:
+
+ /**
+ * 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-4.8.1/i18n/unicode/choicfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/choicfmt.h
new file mode 100644
index 00000000000..663d45aa5b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/choicfmt.h
@@ -0,0 +1,685 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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/fieldpos.h"
+#include "unicode/format.h"
+#include "unicode/messagepattern.h"
+#include "unicode/numfmt.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+class MessageFormat;
+
+/**
+ * ChoiceFormat converts between ranges of numeric values and strings for those ranges.
+ * The strings must conform to the MessageFormat pattern syntax.
+ *
+ * <p><em><code>ChoiceFormat</code> is probably not what you need.
+ * Please use <code>MessageFormat</code>
+ * with <code>plural</code> arguments for proper plural selection,
+ * and <code>select</code> arguments for simple selection among a fixed set of choices!</em></p>
+ *
+ * <p>A <code>ChoiceFormat</code> splits
+ * the real number line \htmlonly<code>-&#x221E;</code> to
+ * <code>+&#x221E;</code>\endhtmlonly into two
+ * or more contiguous ranges. Each range is mapped to a
+ * string.</p>
+ *
+ * <p><code>ChoiceFormat</code> was originally intended
+ * for displaying grammatically correct
+ * plurals such as &quot;There is one file.&quot; vs. &quot;There are 2 files.&quot;
+ * <em>However,</em> plural rules for many languages
+ * are too complex for the capabilities of ChoiceFormat,
+ * and its requirement of specifying the precise rules for each message
+ * is unmanageable for translators.</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 logically make up the
+ * <code>ChoiceFormat</code>.</p>
+ *
+ * <p>Note: Typically, choice formatting is done (if done at all) via <code>MessageFormat</code>
+ * with a <code>choice</code> argument type,
+ * rather than using a stand-alone <code>ChoiceFormat</code>.</p>
+ *
+ * <h5>Patterns and Their Interpretation</h5>
+ *
+ * <p>The pattern string defines the range boundaries and the strings for each number range.
+ * Syntax:
+ * <pre>
+ * choiceStyle = number separator message ('|' number separator message)*
+ * number = normal_number | ['-'] \htmlonly&#x221E;\endhtmlonly (U+221E, infinity)
+ * normal_number = double value (unlocalized ASCII string)
+ * separator = less_than | less_than_or_equal
+ * less_than = '<'
+ * less_than_or_equal = '#' | \htmlonly&#x2264;\endhtmlonly (U+2264)
+ * message: see {@link MessageFormat}
+ * </pre>
+ * Pattern_White_Space between syntax elements is ignored, except
+ * around each range's sub-message.</p>
+ *
+ * <p>Each numeric sub-range extends from the current range's number
+ * to the next range's number.
+ * The number itself is included in its range if a <code>less_than_or_equal</code> sign is used,
+ * and excluded from its range (and instead included in the previous range)
+ * if a <code>less_than</code> sign is used.</p>
+ *
+ * <p>When a <code>ChoiceFormat</code> is constructed from
+ * arrays of numbers, closure flags and strings,
+ * they are interpreted just like
+ * the sequence of <code>(number separator string)</code> in an equivalent pattern string.
+ * <code>closure[i]==TRUE</code> corresponds to a <code>less_than</code> separator sign.
+ * The equivalent pattern string will be constructed automatically.</p>
+ *
+ * <p>During formatting, a number is mapped to the first range
+ * where the number is not greater than the range's upper limit.
+ * That range's message string is returned. A NaN maps to the very first range.</p>
+ *
+ * <p>During parsing, a range is selected for the longest match of
+ * any range's message. That range's number is returned, ignoring the separator/closure.
+ * Only a simple string match is performed, without parsing of arguments that
+ * might be specified in the message strings.</p>
+ *
+ * <p>Note that the first range's number is ignored in formatting
+ * but may be returned from parsing.</p>
+ *
+ * <h5>Examples</h5>
+ *
+ * <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.
+ * (The round parentheses in the notation above indicate an exclusive boundary,
+ * like the turned bracket in European notation: [-Inf, 1) == [-Inf, 1[ )</p>
+ *
+ * <pre> {0, 1, 1},
+ * {FALSE, FALSE, TRUE},
+ * {&quot;no files&quot;, &quot;one file&quot;, &quot;many files&quot;}</pre>
+ *
+ * <p>Here is an 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><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:
+ /**
+ * Constructs a new ChoiceFormat from the pattern string.
+ *
+ * @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);
+
+
+ /**
+ * Constructs a new ChoiceFormat with the given limits and message strings.
+ * All closure flags default to <code>FALSE</code>,
+ * equivalent to <code>less_than_or_equal</code> separators.
+ *
+ * Copies 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 );
+
+ /**
+ * Constructs a new ChoiceFormat with the given limits, closure flags and message strings.
+ *
+ * Copies the limits and formats instead of adopting them.
+ *
+ * @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 number is a member of its range.
+ * If TRUE, then the limit number belongs to the previous range 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();
+
+ /**
+ * Clones this Format object. The caller owns the
+ * result and must delete it when done.
+ *
+ * @return a copy of this object
+ * @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 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 receive 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 receive the pattern
+ * Previous contents are deleted.
+ * @return A reference to 'pattern'
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString &pattern) const;
+
+ /**
+ * Sets the choices to be used in formatting.
+ * For details see the constructor with the same parameter list.
+ *
+ * @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 );
+
+ /**
+ * Sets the choices to be used in formatting.
+ * For details see the constructor with the same parameter list.
+ *
+ * @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);
+
+ /**
+ * Returns NULL and 0.
+ * Before ICU 4.8, this used to return the choice limits array.
+ *
+ * @param count Will be set to 0.
+ * @return NULL
+ * @deprecated ICU 4.8 Use the MessagePattern class to analyze a ChoiceFormat pattern.
+ */
+ virtual const double* getLimits(int32_t& count) const;
+
+ /**
+ * Returns NULL and 0.
+ * Before ICU 4.8, this used to return the limit booleans array.
+ *
+ * @param count Will be set to 0.
+ * @return NULL
+ * @deprecated ICU 4.8 Use the MessagePattern class to analyze a ChoiceFormat pattern.
+ */
+ virtual const UBool* getClosures(int32_t& count) const;
+
+ /**
+ * Returns NULL and 0.
+ * Before ICU 4.8, this used to return the array of choice strings.
+ *
+ * @param count Will be set to 0.
+ * @return NULL
+ * @deprecated ICU 4.8 Use the MessagePattern class to analyze a ChoiceFormat pattern.
+ */
+ virtual const UnicodeString* getFormats(int32_t& count) const;
+
+
+ using NumberFormat::format;
+
+ /**
+ * Formats a double 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;
+ /**
+ * Formats an int32_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.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Formats 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;
+
+ /**
+ * Formats 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;
+ /**
+ * Formats 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.
+ * Formats 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.
+ * Formats an int32_t 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;
+
+ /**
+ * Looks for the longest match of any message string on the input text and,
+ * if there is a match, sets the result object to the corresponding range's number.
+ *
+ * If no string matches, then the parsePosition is unchanged.
+ *
+ * @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.
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const;
+
+ /**
+ * Looks for the longest match of any message string on the input text and,
+ * if there is a match, sets the result object to the corresponding range's number.
+ *
+ * If no string matches, then the UErrorCode is set to U_INVALID_FORMAT_ERROR.
+ *
+ * @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.
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const;
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Part of ICU's "poor man's RTTI".
+ *
+ * @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);
+
+private:
+ /**
+ * Converts a double value to a string.
+ * @param value the double number to be converted.
+ * @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 receive 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;
+
+ virtual void setChoices(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t count,
+ UErrorCode &errorCode);
+
+ /**
+ * Finds the ChoiceFormat sub-message for the given number.
+ * @param pattern A MessagePattern.
+ * @param partIndex the index of the first ChoiceFormat argument style part.
+ * @param number a number to be mapped to one of the ChoiceFormat argument's intervals
+ * @return the sub-message start part index.
+ */
+ static int32_t findSubMessage(const MessagePattern &pattern, int32_t partIndex, double number);
+
+ static double parseArgument(
+ const MessagePattern &pattern, int32_t partIndex,
+ const UnicodeString &source, ParsePosition &pos);
+
+ /**
+ * Matches the pattern string from the end of the partIndex to
+ * the beginning of the limitPartIndex,
+ * including all syntax except SKIP_SYNTAX,
+ * against the source string starting at sourceOffset.
+ * If they match, returns the length of the source string match.
+ * Otherwise returns -1.
+ */
+ static int32_t matchStringUntilLimitPart(
+ const MessagePattern &pattern, int32_t partIndex, int32_t limitPartIndex,
+ const UnicodeString &source, int32_t sourceOffset);
+
+ /**
+ * Some of the ChoiceFormat constructors do not have a UErrorCode paramater.
+ * We need _some_ way to provide one for the MessagePattern constructor.
+ * Alternatively, the MessagePattern could be a pointer field, but that is
+ * not nice either.
+ */
+ UErrorCode constructorErrorCode;
+
+ /**
+ * The MessagePattern which contains the parsed structure of the pattern string.
+ *
+ * Starting with ICU 4.8, the MessagePattern contains a sequence of
+ * numeric/selector/message parts corresponding to the parsed pattern.
+ * For details see the MessagePattern class API docs.
+ */
+ MessagePattern msgPattern;
+
+ /**
+ * Docs & fields from before ICU 4.8, before MessagePattern was used.
+ * Commented out, and left only for explanation of semantics.
+ * --------
+ * 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-4.8.1/i18n/unicode/coleitr.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/coleitr.h
new file mode 100644
index 00000000000..4025a41d730
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/coleitr.h
@@ -0,0 +1,400 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1997-2008, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ******************************************************************************
+ */
+
+/**
+ * \file
+ * \brief C++ API: Collation Element Iterator.
+ */
+
+/**
+* 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"
+
+
+#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-4.8.1/i18n/unicode/coll.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/coll.h
new file mode 100644
index 00000000000..e2451bad207
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/coll.h
@@ -0,0 +1,1141 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2011, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C++ API: Collation Service.
+ */
+
+/**
+* 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"
+
+#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"
+#include "unicode/uiter.h"
+#include "unicode/stringpiece.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;
+
+ /**
+ * Compares two strings using the Collator.
+ * Returns whether the first one compares less than/equal to/greater than
+ * the second one.
+ * This version takes UCharIterator input.
+ * @param sIter the first ("source") string iterator
+ * @param tIter the second ("target") string iterator
+ * @param status ICU status
+ * @return UCOL_LESS, UCOL_EQUAL or UCOL_GREATER
+ * @stable ICU 4.2
+ */
+ virtual UCollationResult compare(UCharIterator &sIter,
+ UCharIterator &tIter,
+ UErrorCode &status) const;
+
+ /**
+ * Compares two UTF-8 strings using the Collator.
+ * Returns whether the first one compares less than/equal to/greater than
+ * the second one.
+ * This version takes UTF-8 input.
+ * Note that a StringPiece can be implicitly constructed
+ * from a std::string or a NUL-terminated const char * string.
+ * @param source the first UTF-8 string
+ * @param target the second UTF-8 string
+ * @param status ICU status
+ * @return UCOL_LESS, UCOL_EQUAL or UCOL_GREATER
+ * @stable ICU 4.2
+ */
+ virtual UCollationResult compareUTF8(const StringPiece &source,
+ const StringPiece &target,
+ UErrorCode &status) const;
+
+ /**
+ * 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;
+
+ /**
+ * Retrieves the reordering codes for this collator.
+ * @param dest The array to fill with the script ordering.
+ * @param destCapacity The length of dest. If it is 0, then dest may be NULL and the function
+ * will only return the length of the result without writing any of the result string (pre-flighting).
+ * @param status A reference to an error code value, which must not indicate
+ * a failure before the function call.
+ * @return The length of the script ordering array.
+ * @see ucol_setReorderCodes
+ * @see Collator#getEquivalentReorderCodes
+ * @see Collator#setReorderCodes
+ * @draft ICU 4.8
+ */
+ virtual int32_t U_EXPORT2 getReorderCodes(int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode& status) const;
+
+ /**
+ * Sets the ordering of scripts for this collator.
+ * @param reorderCodes An array of script codes in the new order. This can be NULL if the
+ * length is also set to 0. An empty array will clear any reordering codes on the collator.
+ * @param reorderCodesLength The length of reorderCodes.
+ * @see Collator#getReorderCodes
+ * @see Collator#getEquivalentReorderCodes
+ * @param status error code
+ * @draft ICU 4.8
+ */
+ virtual void U_EXPORT2 setReorderCodes(const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode& status) ;
+
+ /**
+ * Retrieves the reorder codes that are grouped with the given reorder code. Some reorder
+ * codes will be grouped and must reorder together.
+ * @param reorderCode The reorder code to determine equivalence for.
+ * @param dest The array to fill with the script equivalene reordering codes.
+ * @param destCapacity The length of dest. If it is 0, then dest may be NULL and the
+ * function will only return the length of the result without writing any of the result
+ * string (pre-flighting).
+ * @param status A reference to an error code value, which must not indicate
+ * a failure before the function call.
+ * @return The length of the of the reordering code equivalence array.
+ * @see ucol_setReorderCodes
+ * @see Collator#getReorderCodes
+ * @see Collator#setReorderCodes
+ * @draft ICU 4.8
+ */
+ static int32_t U_EXPORT2 getEquivalentReorderCodes(int32_t reorderCode,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode& status);
+
+ /**
+ * 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);
+
+ /**
+ * Given a key and a locale, returns an array of string values in a preferred
+ * order that would make a difference. These are all and only those values where
+ * the open (creation) of the service with the locale formed from the input locale
+ * plus input keyword and that value has different behavior than creation with the
+ * input locale alone.
+ * @param keyword one of the keys supported by this service. For now, only
+ * "collation" is supported.
+ * @param locale the locale
+ * @param commonlyUsed if set to true it will return only commonly used values
+ * with the given locale in preferred order. Otherwise,
+ * it will return all the available values for the locale.
+ * @param status ICU status
+ * @return a string enumeration over keyword values for the given key and the locale.
+ * @stable ICU 4.2
+ */
+ static StringEnumeration* U_EXPORT2 getKeywordValuesForLocale(const char* keyword, const Locale& locale,
+ UBool commonlyUsed, 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 requested locale
+ * @param validLocale the valid locale
+ * @param actualLocale the actual locale
+ * @internal
+ */
+ virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale, const Locale& actualLocale);
+
+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-4.8.1/i18n/unicode/colldata.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/colldata.h
new file mode 100644
index 00000000000..af465f59208
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/colldata.h
@@ -0,0 +1,452 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines *
+ * Corporation and others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+/**
+ * \file
+ * \brief C++ API: Collation data used to compute minLengthInChars.
+ * \internal
+ */
+
+#ifndef COLL_DATA_H
+#define COLL_DATA_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uobject.h"
+#include "unicode/ucol.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * The size of the internal buffer for the Collator's short description string.
+ * @internal ICU 4.0.1 technology preview
+ */
+#define KEY_BUFFER_SIZE 64
+
+ /**
+ * The size of the internal CE buffer in a <code>CEList</code> object
+ * @internal ICU 4.0.1 technology preview
+ */
+#define CELIST_BUFFER_SIZE 4
+
+/**
+ * \def INSTRUMENT_CELIST
+ * Define this to enable the <code>CEList</code> objects to collect
+ * statistics.
+ * @internal ICU 4.0.1 technology preview
+ */
+//#define INSTRUMENT_CELIST
+
+ /**
+ * The size of the initial list in a <code>StringList</code> object.
+ * @internal ICU 4.0.1 technology preview
+ */
+#define STRING_LIST_BUFFER_SIZE 16
+
+/**
+ * \def INSTRUMENT_STRING_LIST
+ * Define this to enable the <code>StringList</code> objects to
+ * collect statistics.
+ * @internal ICU 4.0.1 technology preview
+ */
+//#define INSTRUMENT_STRING_LIST
+
+ /**
+ * This object holds a list of CEs generated from a particular
+ * <code>UnicodeString</code>
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+class U_I18N_API CEList : public UObject
+{
+public:
+ /**
+ * Construct a <code>CEList</code> object.
+ *
+ * @param coll - the Collator used to collect the CEs.
+ * @param string - the string for which to collect the CEs.
+ * @param status - will be set if any errors occur.
+ *
+ * Note: if on return, status is set to an error code,
+ * the only safe thing to do with this object is to call
+ * the destructor.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ CEList(UCollator *coll, const UnicodeString &string, UErrorCode &status);
+
+ /**
+ * The destructor.
+ * @internal ICU 4.0.1 technology preview
+ */
+ ~CEList();
+
+ /**
+ * Return the number of CEs in the list.
+ *
+ * @return the number of CEs in the list.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ int32_t size() const;
+
+ /**
+ * Get a particular CE from the list.
+ *
+ * @param index - the index of the CE to return
+ *
+ * @return the CE, or <code>0</code> if <code>index</code> is out of range
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ uint32_t get(int32_t index) const;
+
+ /**
+ * Check if the CEs in another <code>CEList</code> match the
+ * suffix of this list starting at a give offset.
+ *
+ * @param offset - the offset of the suffix
+ * @param other - the other <code>CEList</code>
+ *
+ * @return <code>TRUE</code> if the CEs match, <code>FALSE</code> otherwise.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ UBool matchesAt(int32_t offset, const CEList *other) const;
+
+ /**
+ * The index operator.
+ *
+ * @param index - the index
+ *
+ * @return a reference to the given CE in the list
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ uint32_t &operator[](int32_t index) const;
+
+ /**
+ * UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ virtual UClassID getDynamicClassID() const;
+ /**
+ * UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ static UClassID getStaticClassID();
+
+private:
+ void add(uint32_t ce, UErrorCode &status);
+
+ uint32_t ceBuffer[CELIST_BUFFER_SIZE];
+ uint32_t *ces;
+ int32_t listMax;
+ int32_t listSize;
+
+#ifdef INSTRUMENT_CELIST
+ static int32_t _active;
+ static int32_t _histogram[10];
+#endif
+};
+
+/**
+ * StringList
+ *
+ * This object holds a list of <code>UnicodeString</code> objects.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+class U_I18N_API StringList : public UObject
+{
+public:
+ /**
+ * Construct an empty <code>StringList</code>
+ *
+ * @param status - will be set if any errors occur.
+ *
+ * Note: if on return, status is set to an error code,
+ * the only safe thing to do with this object is to call
+ * the destructor.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ StringList(UErrorCode &status);
+
+ /**
+ * The destructor.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ ~StringList();
+
+ /**
+ * Add a string to the list.
+ *
+ * @param string - the string to add
+ * @param status - will be set if any errors occur.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ void add(const UnicodeString *string, UErrorCode &status);
+
+ /**
+ * Add an array of Unicode code points to the list.
+ *
+ * @param chars - the address of the array of code points
+ * @param count - the number of code points in the array
+ * @param status - will be set if any errors occur.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ void add(const UChar *chars, int32_t count, UErrorCode &status);
+
+ /**
+ * Get a particular string from the list.
+ *
+ * @param index - the index of the string
+ *
+ * @return a pointer to the <code>UnicodeString</code> or <code>NULL</code>
+ * if <code>index</code> is out of bounds.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ const UnicodeString *get(int32_t index) const;
+
+ /**
+ * Get the number of stings in the list.
+ *
+ * @return the number of strings in the list.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ int32_t size() const;
+
+ /**
+ * the UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ virtual UClassID getDynamicClassID() const;
+ /**
+ * the UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ static UClassID getStaticClassID();
+
+private:
+ UnicodeString *strings;
+ int32_t listMax;
+ int32_t listSize;
+
+#ifdef INSTRUMENT_STRING_LIST
+ static int32_t _lists;
+ static int32_t _strings;
+ static int32_t _histogram[101];
+#endif
+};
+
+/*
+ * Forward references to internal classes.
+ */
+class StringToCEsMap;
+class CEToStringsMap;
+class CollDataCache;
+
+/**
+ * CollData
+ *
+ * This class holds the Collator-specific data needed to
+ * compute the length of the shortest string that can
+ * generate a partcular list of CEs.
+ *
+ * <code>CollData</code> objects are quite expensive to compute. Because
+ * of this, they are cached. When you call <code>CollData::open</code> it
+ * returns a reference counted cached object. When you call <code>CollData::close</code>
+ * the reference count on the object is decremented but the object is not deleted.
+ *
+ * If you do not need to reuse any unreferenced objects in the cache, you can call
+ * <code>CollData::flushCollDataCache</code>. If you no longer need any <code>CollData</code>
+ * objects, you can call <code>CollData::freeCollDataCache</code>
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+class U_I18N_API CollData : public UObject
+{
+public:
+ /**
+ * Construct a <code>CollData</code> object.
+ *
+ * @param collator - the collator
+ * @param status - will be set if any errors occur.
+ *
+ * @return the <code>CollData</code> object. You must call
+ * <code>close</code> when you are done using the object.
+ *
+ * Note: if on return, status is set to an error code,
+ * the only safe thing to do with this object is to call
+ * <code>CollData::close</code>.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ static CollData *open(UCollator *collator, UErrorCode &status);
+
+ /**
+ * Release a <code>CollData</code> object.
+ *
+ * @param collData - the object
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ static void close(CollData *collData);
+
+ /**
+ * Get the <code>UCollator</code> object used to create this object.
+ * The object returned may not be the exact object that was used to
+ * create this object, but it will have the same behavior.
+ * @internal ICU 4.0.1 technology preview
+ */
+ UCollator *getCollator() const;
+
+ /**
+ * Get a list of all the strings which generate a list
+ * of CEs starting with a given CE.
+ *
+ * @param ce - the CE
+ *
+ * return a <code>StringList</code> object containing all
+ * the stirngs, or <code>NULL</code> if there are
+ * no such strings.
+ *
+ * @internal ICU 4.0.1 technology preview.
+ */
+ const StringList *getStringList(int32_t ce) const;
+
+ /**
+ * Get a list of the CEs generated by a partcular stirng.
+ *
+ * @param string - the string
+ *
+ * @return a <code>CEList</code> object containt the CEs. You
+ * must call <code>freeCEList</code> when you are finished
+ * using the <code>CEList</code>/
+ *
+ * @internal ICU 4.0.1 technology preview.
+ */
+ const CEList *getCEList(const UnicodeString *string) const;
+
+ /**
+ * Release a <code>CEList</code> returned by <code>getCEList</code>.
+ *
+ * @param list - the <code>CEList</code> to free.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ void freeCEList(const CEList *list);
+
+ /**
+ * Return the length of the shortest string that will generate
+ * the given list of CEs.
+ *
+ * @param ces - the CEs
+ * @param offset - the offset of the first CE in the list to use.
+ *
+ * @return the length of the shortest string.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ int32_t minLengthInChars(const CEList *ces, int32_t offset) const;
+
+
+ /**
+ * Return the length of the shortest string that will generate
+ * the given list of CEs.
+ *
+ * Note: the algorithm used to do this computation is recursive. To
+ * limit the amount of recursion, a "history" list is used to record
+ * the best answer starting at a particular offset in the list of CEs.
+ * If the same offset is visited again during the recursion, the answer
+ * in the history list is used.
+ *
+ * @param ces - the CEs
+ * @param offset - the offset of the first CE in the list to use.
+ * @param history - the history list. Must be at least as long as
+ * the number of cEs in the <code>CEList</code>
+ *
+ * @return the length of the shortest string.
+ *
+ * @internal ICU 4.0.1 technology preview
+ */
+ int32_t minLengthInChars(const CEList *ces, int32_t offset, int32_t *history) const;
+
+ /**
+ * UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ virtual UClassID getDynamicClassID() const;
+ /**
+ * UObject glue...
+ * @internal ICU 4.0.1 technology preview
+ */
+ static UClassID getStaticClassID();
+
+ /**
+ * <code>CollData</code> objects are expensive to compute, and so
+ * may be cached. This routine will free the cached objects and delete
+ * the cache.
+ *
+ * WARNING: Don't call this until you are have called <code>close</code>
+ * for each <code>CollData</code> object that you have used. also,
+ * DO NOT call this if another thread may be calling <code>flushCollDataCache</code>
+ * at the same time.
+ *
+ * @internal 4.0.1 technology preview
+ */
+ static void freeCollDataCache();
+
+ /**
+ * <code>CollData</code> objects are expensive to compute, and so
+ * may be cached. This routine will remove any unused <code>CollData</code>
+ * objects from the cache.
+ *
+ * @internal 4.0.1 technology preview
+ */
+ static void flushCollDataCache();
+
+private:
+ friend class CollDataCache;
+ friend class CollDataCacheEntry;
+
+ CollData(UCollator *collator, char *cacheKey, int32_t cachekeyLength, UErrorCode &status);
+ ~CollData();
+
+ CollData();
+
+ static char *getCollatorKey(UCollator *collator, char *buffer, int32_t bufferLength);
+
+ static CollDataCache *getCollDataCache();
+
+ UCollator *coll;
+ StringToCEsMap *charsToCEList;
+ CEToStringsMap *ceToCharsStartingWith;
+
+ char keyBuffer[KEY_BUFFER_SIZE];
+ char *key;
+
+ static CollDataCache *collDataCache;
+
+ uint32_t minHan;
+ uint32_t maxHan;
+
+ uint32_t jamoLimits[4];
+};
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_COLLATION
+#endif // #ifndef COLL_DATA_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/curramt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/curramt.h
new file mode 100644
index 00000000000..c33e6f1f833
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/currpinf.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/currpinf.h
new file mode 100644
index 00000000000..0f6781012d7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/currpinf.h
@@ -0,0 +1,260 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2011, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+#ifndef CURRPINF_H
+#define CURRPINF_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Currency Plural Information used by Decimal Format
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+
+union UHashTok;
+
+U_NAMESPACE_BEGIN
+
+class Locale;
+class PluralRules;
+class Hashtable;
+
+/**
+ * This class represents the information needed by
+ * DecimalFormat to format currency plural,
+ * such as "3.00 US dollars" or "1.00 US dollar".
+ * DecimalFormat creates for itself an instance of
+ * CurrencyPluralInfo from its locale data.
+ * If you need to change any of these symbols, you can get the
+ * CurrencyPluralInfo object from your
+ * DecimalFormat and modify it.
+ *
+ * Following are the information needed for currency plural format and parse:
+ * locale information,
+ * plural rule of the locale,
+ * currency plural pattern of the locale.
+ *
+ * @stable ICU 4.2
+ */
+class U_I18N_API CurrencyPluralInfo : public UObject {
+public:
+
+ /**
+ * Create a CurrencyPluralInfo object for the default locale.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ CurrencyPluralInfo(UErrorCode& status);
+
+ /**
+ * Create a CurrencyPluralInfo object for the given locale.
+ * @param locale the locale
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ CurrencyPluralInfo(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Copy constructor
+ *
+ * @stable ICU 4.2
+ */
+ CurrencyPluralInfo(const CurrencyPluralInfo& info);
+
+
+ /**
+ * Assignment operator
+ *
+ * @stable ICU 4.2
+ */
+ CurrencyPluralInfo& operator=(const CurrencyPluralInfo& info);
+
+
+ /**
+ * Destructor
+ *
+ * @stable ICU 4.2
+ */
+ virtual ~CurrencyPluralInfo();
+
+
+ /**
+ * Equal operator.
+ *
+ * @stable ICU 4.2
+ */
+ UBool operator==(const CurrencyPluralInfo& info) const;
+
+
+ /**
+ * Not equal operator
+ *
+ * @stable ICU 4.2
+ */
+ UBool operator!=(const CurrencyPluralInfo& info) const;
+
+
+ /**
+ * Clone
+ *
+ * @stable ICU 4.2
+ */
+ CurrencyPluralInfo* clone() const;
+
+
+ /**
+ * Gets plural rules of this locale, used for currency plural format
+ *
+ * @return plural rule
+ * @stable ICU 4.2
+ */
+ const PluralRules* getPluralRules() const;
+
+ /**
+ * Given a plural count, gets currency plural pattern of this locale,
+ * used for currency plural format
+ *
+ * @param pluralCount currency plural count
+ * @param result output param to receive the pattern
+ * @return a currency plural pattern based on plural count
+ * @stable ICU 4.2
+ */
+ UnicodeString& getCurrencyPluralPattern(const UnicodeString& pluralCount,
+ UnicodeString& result) const;
+
+ /**
+ * Get locale
+ *
+ * @return locale
+ * @stable ICU 4.2
+ */
+ const Locale& getLocale() const;
+
+ /**
+ * Set plural rules.
+ * The plural rule is set when CurrencyPluralInfo
+ * instance is created.
+ * You can call this method to reset plural rules only if you want
+ * to modify the default plural rule of the locale.
+ *
+ * @param ruleDescription new plural rule description
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ void setPluralRules(const UnicodeString& ruleDescription,
+ UErrorCode& status);
+
+ /**
+ * Set currency plural pattern.
+ * The currency plural pattern is set when CurrencyPluralInfo
+ * instance is created.
+ * You can call this method to reset currency plural pattern only if
+ * you want to modify the default currency plural pattern of the locale.
+ *
+ * @param pluralCount the plural count for which the currency pattern will
+ * be overridden.
+ * @param pattern the new currency plural pattern
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ void setCurrencyPluralPattern(const UnicodeString& pluralCount,
+ const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Set locale
+ *
+ * @param loc the new locale to set
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ void setLocale(const Locale& loc, UErrorCode& status);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 4.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 4.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ friend class DecimalFormat;
+
+ void initialize(const Locale& loc, UErrorCode& status);
+
+ void setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status);
+
+ /*
+ * delete hash table
+ *
+ * @param hTable hash table to be deleted
+ */
+ void deleteHash(Hashtable* hTable);
+
+
+ /*
+ * initialize hash table
+ *
+ * @param status output param set to success/failure code on exit
+ * @return hash table initialized
+ */
+ Hashtable* initHash(UErrorCode& status);
+
+
+
+ /**
+ * copy hash table
+ *
+ * @param source the source to copy from
+ * @param target the target to copy to
+ * @param status error code
+ */
+ void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
+
+ //-------------------- private data member ---------------------
+ // map from plural count to currency plural pattern, for example
+ // a plural pattern defined in "CurrencyUnitPatterns" is
+ // "one{{0} {1}}", in which "one" is a plural count
+ // and "{0} {1}" is a currency plural pattern".
+ // The currency plural pattern saved in this mapping is the pattern
+ // defined in "CurrencyUnitPattern" by replacing
+ // {0} with the number format pattern,
+ // and {1} with 3 currency sign.
+ Hashtable* fPluralCountToCurrencyUnitPattern;
+
+ /*
+ * The plural rule is used to format currency plural name,
+ * for example: "3.00 US Dollars".
+ * If there are 3 currency signs in the currency patttern,
+ * the 3 currency signs will be replaced by currency plural name.
+ */
+ PluralRules* fPluralRules;
+
+ // locale
+ Locale* fLocale;
+};
+
+
+inline UBool
+CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { return !operator==(info); }
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CURRPINFO
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/currunit.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/currunit.h
new file mode 100644
index 00000000000..ecd94110292
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/datefmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/datefmt.h
new file mode 100644
index 00000000000..c79dec89124
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/datefmt.h
@@ -0,0 +1,751 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2011, 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;
+class DateTimePatternGenerator;
+
+/**
+ * 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,
+ * the default date-time pattern, and 4 date-time patterns. 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,
+ // Default DateTime
+
+ kDateTimeOffset = kDateTime + 1,
+ // kFull + kDateTimeOffset = 9
+ // kLong + kDateTimeOffset = 10
+ // kMedium + kDateTimeOffset = 11
+ // kShort + kDateTimeOffset = 12
+
+ // 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;
+
+
+ using Format::format;
+
+ /**
+ * 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;
+
+ /**
+ * 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Field values
+ * are defined in UDateFormatField. Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ 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. When the calendar type is
+ * different from the internal calendar held by this
+ * DateFormat instance, the date and the time zone will
+ * be inherited from the input calendar, but other calendar
+ * field values will be calculated by the internal calendar.
+ * @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 date into a date/time string. Subclasses should implement this method.
+ *
+ * @param cal Calendar set to the date and time to be formatted
+ * into a date/time string. When the calendar type is
+ * different from the internal calendar held by this
+ * DateFormat instance, the date and the time zone will
+ * be inherited from the input calendar, but other calendar
+ * field values will be calculated by the internal calendar.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Field values
+ * are defined in UDateFormatField. Can be NULL.
+ * @param status error status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& format(Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+ /**
+ * 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.
+ *
+ * @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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Field values
+ * are defined in UDateFormatField. Can be NULL.
+ * @param status error status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ UnicodeString& format(UDate date,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) 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. When the calendar type
+ * is different from the internal calendar held by this
+ * DateFormat instance, calendar field values will be
+ * parsed based on the internal calendar, then the result
+ * (time in milliseconds and time zone) will be set in
+ * this calendar.
+ * @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. Relative
+ * time styles are not currently supported.
+ * @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. Relative
+ * time styles are not currently supported.
+ * @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& inLocale);
+
+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-4.8.1/i18n/unicode/dcfmtsym.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dcfmtsym.h
new file mode 100644
index 00000000000..0c8e89c6f49
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dcfmtsym.h
@@ -0,0 +1,450 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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"
+#include "unicode/uchar.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/locid.h"
+#include "unicode/unum.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,
+ /** One
+ * @draft ICU 4.6
+ */
+ kOneDigitSymbol,
+ /** Two
+ * @draft ICU 4.6
+ */
+ kTwoDigitSymbol,
+ /** Three
+ * @draft ICU 4.6
+ */
+ kThreeDigitSymbol,
+ /** Four
+ * @draft ICU 4.6
+ */
+ kFourDigitSymbol,
+ /** Five
+ * @draft ICU 4.6
+ */
+ kFiveDigitSymbol,
+ /** Six
+ * @draft ICU 4.6
+ */
+ kSixDigitSymbol,
+ /** Seven
+ * @draft ICU 4.6
+ */
+ kSevenDigitSymbol,
+ /** Eight
+ * @draft ICU 4.6
+ */
+ kEightDigitSymbol,
+ /** Nine
+ * @draft ICU 4.6
+ */
+ kNineDigitSymbol,
+ /** 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 modifier 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 modifier letters) can be used.
+ *
+ * @param symbol Constant to indicate a number format symbol.
+ * @param value value of the format symbol
+ * @param propogateDigits If false, setting the zero digit will not automatically set 1-9.
+ * The default behavior is to automatically set 1-9 if zero is being set and the value
+ * it is being set to corresponds to a known Unicode zero digit.
+ * @stable ICU 2.0
+ */
+ void setSymbol(ENumberFormatSymbol symbol, const UnicodeString &value, const UBool propogateDigits);
+
+ /**
+ * 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;
+
+ /**
+ * Get pattern string for 'CurrencySpacing' that can be applied to
+ * currency format.
+ * This API gets the CurrencySpacing data from ResourceBundle. The pattern can
+ * be empty if there is no data from current locale and its parent locales.
+ *
+ * @param type : UNUM_CURRENCY_MATCH, UNUM_CURRENCY_SURROUNDING_MATCH or UNUM_CURRENCY_INSERT.
+ * @param beforeCurrency : true if the pattern is for before currency symbol.
+ * false if the pattern is for after currency symbol.
+ * @param status: Input/output parameter, set to success or
+ * failure code upon return.
+ * @return pattern string for currencyMatch, surroundingMatch or spaceInsert.
+ * Return empty string if there is no data for this locale and its parent
+ * locales.
+ * @draft ICU 4.8
+ */
+ const UnicodeString& getPatternForCurrencySpacing(UCurrencySpacing type,
+ UBool beforeCurrency,
+ UErrorCode& status) const;
+ /**
+ * Set pattern string for 'CurrencySpacing' that can be applied to
+ * currency format.
+ *
+ * @param type : UNUM_CURRENCY_MATCH, UNUM_CURRENCY_SURROUNDING_MATCH or UNUM_CURRENCY_INSERT.
+ * @param beforeCurrency : true if the pattern is for before currency symbol.
+ * false if the pattern is for after currency symbol.
+ * @param pattern : pattern string to override current setting.
+ * @draft ICU 4.8
+ */
+ void setPatternForCurrencySpacing(UCurrencySpacing type,
+ UBool beforeCurrency,
+ const UnicodeString& pattern);
+
+ /**
+ * 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 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;
+
+ UnicodeString currencySpcBeforeSym[UNUM_CURRENCY_SPACING_COUNT];
+ UnicodeString currencySpcAfterSym[UNUM_CURRENCY_SPACING_COUNT];
+};
+
+// -------------------------------------
+
+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, const UBool propogateDigits = TRUE) {
+ if(symbol<kFormatSymbolCount) {
+ fSymbols[symbol]=value;
+ }
+
+ // If the zero digit is being set to a known zero digit according to Unicode,
+ // then we automatically set the corresponding 1-9 digits
+ if ( propogateDigits && symbol == kZeroDigitSymbol && value.countChar32() == 1 ) {
+ UChar32 sym = value.char32At(0);
+ if ( u_charDigitValue(sym) == 0 ) {
+ for ( int8_t i = 1 ; i<= 9 ; i++ ) {
+ sym++;
+ fSymbols[(int)kOneDigitSymbol+i-1] = UnicodeString(sym);
+ }
+ }
+ }
+}
+
+// -------------------------------------
+
+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-4.8.1/i18n/unicode/decimfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/decimfmt.h
new file mode 100644
index 00000000000..048ee858aac
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/decimfmt.h
@@ -0,0 +1,2320 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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"
+#include "unicode/fpositer.h"
+#include "unicode/stringpiece.h"
+
+union UHashTok;
+
+U_NAMESPACE_BEGIN
+
+class DigitList;
+class ChoiceFormat;
+class CurrencyPluralInfo;
+class Hashtable;
+class UnicodeSet;
+class FieldPositionHandler;
+
+/**
+ * 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", "USD123",
+ * "123 US dollars"). 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>
+ * Another example use createInstance(style)
+ * <P>
+ * <pre>
+ * <strong>// Print out a number using the localized number, currency,
+ * // percent, scientific, integer, iso currency, and plural currency
+ * // format for each locale</strong>
+ * Locale* locale = new Locale("en", "US");
+ * double myNumber = 1234.56;
+ * UErrorCode success = U_ZERO_ERROR;
+ * UnicodeString str;
+ * Formattable fmtable;
+ * for (int j=NumberFormat::kNumberStyle;
+ * j<=NumberFormat::kPluralCurrencyStyle;
+ * ++j) {
+ * NumberFormat* format = NumberFormat::createInstance(locale, j, success);
+ * str.remove();
+ * cout << "format result " << form->format(myNumber, str) << endl;
+ * format->parse(form->format(myNumber, str), fmtable, success);
+ * }</pre>
+ *
+ *
+ * <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 tripled, replaced by currency plural names, for example,
+ * "US dollar" or "US dollars" for America.
+ * 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 if in lenient mode;
+ * otherwise, if present, they must be in appropriate positions.
+ *
+ * <p>For currency parsing, the formatter is able to parse every currency
+ * style formats no matter which style the formatter is constructed with.
+ * For example, a formatter instance gotten from
+ * NumberFormat.getInstance(ULocale, NumberFormat.CURRENCYSTYLE) can parse
+ * formats such as "USD1.00" and "3.00 US dollars".
+ *
+ * <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 rounding is 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/or 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.
+ *
+ * <p>In the absense of an explicit rounding increment numbers are
+ * rounded to their formatted width.
+ *
+ * <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. The default rounding mode is
+ * DecimalFormat::kRoundHalfEven. The rounding mode can only be set
+ * through the API; it can not be set with a pattern.
+ *
+ * <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 */
+ /**
+ * Return U_FORMAT_INEXACT_ERROR if number does not format exactly.
+ * @draft ICU 4.8
+ */
+ kRoundUnnecessary
+ };
+
+ /**
+ * 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);
+
+ /**
+ * This API is for ICU use only.
+ * Create a DecimalFormat from the given pattern, symbols, and style.
+ *
+ * @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 style style of decimal format
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @internal ICU 4.2
+ */
+ DecimalFormat( const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UNumberFormatStyle style,
+ 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;
+
+
+ using NumberFormat::format;
+
+ /**
+ * 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 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) 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 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) 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 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+
+ /**
+ * Format a decimal number.
+ * The syntax of the unformatted number is a "numeric string"
+ * as defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ *
+ * @param number The unformatted number, as a string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(const StringPiece &number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+
+
+ /**
+ * Format a decimal number.
+ * The number is a DigitList wrapper onto a floating point decimal number.
+ * The default implementation in NumberFormat converts the decimal number
+ * to a double and formats that.
+ *
+ * @param number The number, a DigitList format Decimal Floating Point.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @internal
+ */
+ virtual UnicodeString& format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+
+ /**
+ * Format a decimal number.
+ * The number is a DigitList wrapper onto a floating point decimal number.
+ * The default implementation in NumberFormat converts the decimal number
+ * to a double and formats that.
+ *
+ * @param number The number, a DigitList format Decimal Floating Point.
+ * @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.
+ * @internal
+ */
+ virtual UnicodeString& format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) 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);
+
+
+ /**
+ * Returns the currency plural format information,
+ * which is generally not changed by the programmer or user.
+ * @return desired CurrencyPluralInfo
+ * @stable ICU 4.2
+ */
+ virtual const CurrencyPluralInfo* getCurrencyPluralInfo(void) const;
+
+ /**
+ * Sets the currency plural format information,
+ * which is generally not changed by the programmer or user.
+ * @param toAdopt CurrencyPluralInfo to be adopted.
+ * @stable ICU 4.2
+ */
+ virtual void adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt);
+
+ /**
+ * Sets the currency plural format information,
+ * which is generally not changed by the programmer or user.
+ * @param info Currency Plural Info.
+ * @stable ICU 4.2
+ */
+ virtual void setCurrencyPluralInfo(const CurrencyPluralInfo& info);
+
+
+ /**
+ * 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 a rounding
+ * increment is not in effect.
+ * @see #setRoundingIncrement
+ * @see #getRoundingMode
+ * @see #setRoundingMode
+ * @stable ICU 2.0
+ */
+ virtual double getRoundingIncrement(void) const;
+
+ /**
+ * Set the rounding increment. In the absence of a rounding increment,
+ * numbers will be rounded to the number of digits displayed.
+ * @param newValue A positive rounding increment.
+ * 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.
+ * @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 #EPadPosition
+ * @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 #EPadPosition
+ * @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() const;
+
+ /**
+ * Initialize all fields of a new DecimalFormatter.
+ * Common code for use by constructors.
+ */
+ void init();
+
+ /**
+ * 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);
+
+ /*
+ * similar to applyPattern, but without re-gen affix for currency
+ */
+ void applyPatternInternally(const UnicodeString& pluralCount,
+ const UnicodeString& pattern,
+ UBool localized,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /*
+ * only apply pattern without expand affixes
+ */
+ void applyPatternWithoutExpandAffix(const UnicodeString& pattern,
+ UBool localized,
+ UParseError& parseError,
+ UErrorCode& status);
+
+
+ /*
+ * expand affixes (after apply patter) and re-compute fFormatWidth
+ */
+ void expandAffixAdjustWidth(const UnicodeString* pluralCount);
+
+
+ /**
+ * 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 handler Records information about field positions.
+ * @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,
+ FieldPositionHandler& handler,
+ 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,
+ const UnicodeString* negPrefix,
+ const UnicodeString* negSuffix,
+ const UnicodeString* posPrefix,
+ const UnicodeString* posSuffix,
+ UBool currencyParsing,
+ int8_t type,
+ ParsePosition& parsePosition,
+ DigitList& digits, UBool* status,
+ UChar* currency) const;
+
+ // Mixed style parsing for currency.
+ // It parses against the current currency pattern
+ // using complex affix comparison
+ // parses against the currency plural patterns using complex affix comparison,
+ // and parses against the current pattern using simple affix comparison.
+ UBool parseForCurrency(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,
+ const UnicodeString* affixPat,
+ UBool currencyParsing,
+ int8_t type,
+ UChar* currency) const;
+
+ static int32_t compareSimpleAffix(const UnicodeString& affix,
+ const UnicodeString& input,
+ int32_t pos,
+ UBool lenient);
+
+ static int32_t skipPatternWhiteSpace(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,
+ int8_t type,
+ 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);
+
+ static UBool matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol,
+ UnicodeSet *sset, UChar32 schar);
+
+ /**
+ * 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,
+ FieldPositionHandler& handler,
+ 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,
+ FieldPositionHandler& handler,
+ UBool doFormat,
+ const UnicodeString* pluralCount) const;
+
+ void expandAffixes(const UnicodeString* pluralCount);
+
+ void addPadding(UnicodeString& appendTo,
+ FieldPositionHandler& handler,
+ int32_t prefixLen, int32_t suffixLen) const;
+
+ UBool isGroupingPosition(int32_t pos) const;
+
+ void setCurrencyForSymbols();
+
+ // similar to setCurrency without re-compute the affixes for currency.
+ // If currency changes, the affix pattern for currency is not changed,
+ // but the affix will be changed. So, affixes need to be
+ // re-computed in setCurrency(), but not in setCurrencyInternally().
+ virtual void setCurrencyInternally(const UChar* theCurrency, UErrorCode& ec);
+
+ // set up currency affix patterns for mix parsing.
+ // The patterns saved here are the affix patterns of default currency
+ // pattern and the unique affix patterns of the plural currency patterns.
+ // Those patterns are used by parseForCurrency().
+ void setupCurrencyAffixPatterns(UErrorCode& status);
+
+ // set up the currency affixes used in currency plural formatting.
+ // It sets up both fAffixesForCurrency for currency pattern if the current
+ // pattern contains 3 currency signs,
+ // and it sets up fPluralAffixesForCurrency for currency plural patterns.
+ void setupCurrencyAffixes(const UnicodeString& pattern,
+ UBool setupForCurrentPattern,
+ UBool setupForPluralPattern,
+ UErrorCode& status);
+
+ // hashtable operations
+ Hashtable* initHashForAffixPattern(UErrorCode& status);
+ Hashtable* initHashForAffix(UErrorCode& status);
+
+ void deleteHashForAffixPattern();
+ void deleteHashForAffix(Hashtable*& table);
+
+ void copyHashForAffixPattern(const Hashtable* source,
+ Hashtable* target, UErrorCode& status);
+ void copyHashForAffix(const Hashtable* source,
+ Hashtable* target, UErrorCode& status);
+
+ UnicodeString& _format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPositionHandler& handler) const;
+ UnicodeString& _format(double number,
+ UnicodeString& appendTo,
+ FieldPositionHandler& handler) const;
+ UnicodeString& _format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPositionHandler& handler,
+ UErrorCode &status) const;
+
+ // currency sign count
+ enum {
+ fgCurrencySignCountZero,
+ fgCurrencySignCountInSymbolFormat,
+ fgCurrencySignCountInISOFormat,
+ fgCurrencySignCountInPluralFormat
+ } CurrencySignCount;
+
+ /**
+ * Constants.
+ */
+
+ 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;
+
+ DigitList * fMultiplier; // NULL for multiplier of one
+ int32_t fGroupingSize;
+ int32_t fGroupingSize2;
+ UBool fDecimalSeparatorAlwaysShown;
+ DecimalFormatSymbols* fSymbols;
+
+ UBool fUseSignificantDigits;
+ int32_t fMinSignificantDigits;
+ int32_t fMaxSignificantDigits;
+
+ UBool fUseExponentialNotation;
+ int8_t fMinExponentDigits;
+ UBool fExponentSignAlwaysShown;
+
+ DigitList* fRoundingIncrement; // NULL if no rounding increment specified.
+ ERoundingMode fRoundingMode;
+
+ UChar32 fPad;
+ int32_t fFormatWidth;
+ EPadPosition fPadPosition;
+
+ /*
+ * Following are used for currency format
+ */
+ // pattern used in this formatter
+ UnicodeString fFormatPattern;
+ // style is only valid when decimal formatter is constructed by
+ // DecimalFormat(pattern, decimalFormatSymbol, style)
+ int fStyle;
+ /*
+ * Represents whether this is a currency format, and which
+ * currency format style.
+ * 0: not currency format type;
+ * 1: currency style -- symbol name, such as "$" for US dollar.
+ * 2: currency style -- ISO name, such as USD for US dollar.
+ * 3: currency style -- plural long name, such as "US Dollar" for
+ * "1.00 US Dollar", or "US Dollars" for
+ * "3.00 US Dollars".
+ */
+ int fCurrencySignCount;
+
+
+ /* For currency parsing purose,
+ * Need to remember all prefix patterns and suffix patterns of
+ * every currency format pattern,
+ * including the pattern of default currecny style
+ * and plural currency style. And the patterns are set through applyPattern.
+ */
+ // TODO: innerclass?
+ /* This is not needed in the class declaration, so it is moved into decimfmp.cpp
+ struct AffixPatternsForCurrency : public UMemory {
+ // negative prefix pattern
+ UnicodeString negPrefixPatternForCurrency;
+ // negative suffix pattern
+ UnicodeString negSuffixPatternForCurrency;
+ // positive prefix pattern
+ UnicodeString posPrefixPatternForCurrency;
+ // positive suffix pattern
+ UnicodeString posSuffixPatternForCurrency;
+ int8_t patternType;
+
+ AffixPatternsForCurrency(const UnicodeString& negPrefix,
+ const UnicodeString& negSuffix,
+ const UnicodeString& posPrefix,
+ const UnicodeString& posSuffix,
+ int8_t type) {
+ negPrefixPatternForCurrency = negPrefix;
+ negSuffixPatternForCurrency = negSuffix;
+ posPrefixPatternForCurrency = posPrefix;
+ posSuffixPatternForCurrency = posSuffix;
+ patternType = type;
+ }
+ };
+ */
+
+ /* affix for currency formatting when the currency sign in the pattern
+ * equals to 3, such as the pattern contains 3 currency sign or
+ * the formatter style is currency plural format style.
+ */
+ /* This is not needed in the class declaration, so it is moved into decimfmp.cpp
+ struct AffixesForCurrency : public UMemory {
+ // negative prefix
+ UnicodeString negPrefixForCurrency;
+ // negative suffix
+ UnicodeString negSuffixForCurrency;
+ // positive prefix
+ UnicodeString posPrefixForCurrency;
+ // positive suffix
+ UnicodeString posSuffixForCurrency;
+
+ int32_t formatWidth;
+
+ AffixesForCurrency(const UnicodeString& negPrefix,
+ const UnicodeString& negSuffix,
+ const UnicodeString& posPrefix,
+ const UnicodeString& posSuffix) {
+ negPrefixForCurrency = negPrefix;
+ negSuffixForCurrency = negSuffix;
+ posPrefixForCurrency = posPrefix;
+ posSuffixForCurrency = posSuffix;
+ }
+ };
+ */
+
+ // Affix pattern set for currency.
+ // It is a set of AffixPatternsForCurrency,
+ // each element of the set saves the negative prefix pattern,
+ // negative suffix pattern, positive prefix pattern,
+ // and positive suffix pattern of a pattern.
+ // It is used for currency mixed style parsing.
+ // It is actually is a set.
+ // The set contains the default currency pattern from the locale,
+ // and the currency plural patterns.
+ // Since it is a set, it does not contain duplicated items.
+ // For example, if 2 currency plural patterns are the same, only one pattern
+ // is included in the set. When parsing, we do not check whether the plural
+ // count match or not.
+ Hashtable* fAffixPatternsForCurrency;
+
+ // Following 2 are affixes for currency.
+ // It is a hash map from plural count to AffixesForCurrency.
+ // AffixesForCurrency saves the negative prefix,
+ // negative suffix, positive prefix, and positive suffix of a pattern.
+ // It is used during currency formatting only when the currency sign count
+ // is 3. In which case, the affixes are getting from here, not
+ // from the fNegativePrefix etc.
+ Hashtable* fAffixesForCurrency; // for current pattern
+ Hashtable* fPluralAffixesForCurrency; // for plural pattern
+
+ // Information needed for DecimalFormat to format/parse currency plural.
+ CurrencyPluralInfo* fCurrencyPluralInfo;
+
+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-4.8.1/i18n/unicode/dtfmtsym.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtfmtsym.h
new file mode 100644
index 00000000000..9fbbafb0a35
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtfmtsym.h
@@ -0,0 +1,748 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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;
+
+/**
+ * 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 abbreviated 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 abbreviated 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 narrow era strings. For example: "A" and "B".
+ *
+ * @param count Filled in with length of the array.
+ * @return the narrow era strings.
+ * @stable ICU 4.2
+ */
+ const UnicodeString* getNarrowEras(int32_t& count) const;
+
+ /**
+ * Sets narrow era strings. For example: "A" and "B".
+ * @param narrowEras Array of narrow era strings (DateFormatSymbols retains ownership.)
+ * @param count Filled in with length of the array.
+ * @stable ICU 4.2
+ */
+ void setNarrowEras(const UnicodeString* narrowEras, 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.
+ * <p><b>Note:</b> SimpleDateFormat no longer use the zone strings stored in
+ * a DateFormatSymbols. Therefore, the time zone strings set by this mthod
+ * have no effects in an instance of SimpleDateFormat for formatting time
+ * zones.
+ * @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
+
+ /**
+ * Abbreviated 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;
+
+ /**
+ * Narrow era strings. For example: "A" and "B".
+ */
+ UnicodeString* fNarrowEras;
+ int32_t fNarrowErasCount;
+
+ /**
+ * 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;
+
+ /**
+ * Localized names of time zones in this locale. This is a
+ * two-dimensional array of strings of size n by m,
+ * where m is at least 5 and up to 7. Each of the n rows is an
+ * entry containing the localized names for a single TimeZone.
+ *
+ * Each such row contains (with i ranging from 0..n-1):
+ *
+ * zoneStrings[i][0] - time zone ID
+ * example: America/Los_Angeles
+ * zoneStrings[i][1] - long name of zone in standard time
+ * example: Pacific Standard Time
+ * zoneStrings[i][2] - short name of zone in standard time
+ * example: PST
+ * zoneStrings[i][3] - long name of zone in daylight savings time
+ * example: Pacific Daylight Time
+ * zoneStrings[i][4] - short name of zone in daylight savings time
+ * example: PDT
+ * zoneStrings[i][5] - location name of zone
+ * example: United States (Los Angeles)
+ * zoneStrings[i][6] - long generic name of zone
+ * example: Pacific Time
+ * zoneStrings[i][7] - short generic of zone
+ * example: PT
+ *
+ * The zone ID is not localized; it corresponds to the ID
+ * value associated with a system time zone object. All other entries
+ * are localized names. If a zone does not implement daylight savings
+ * time, the daylight savings time names are ignored.
+ *
+ * Note:CLDR 1.5 introduced metazone and its historical mappings.
+ * This simple two-dimensional array is no longer sufficient to represent
+ * localized names and its historic changes. Since ICU 3.8.1, localized
+ * zone names extracted from ICU locale data is stored in a ZoneStringFormat
+ * instance. But we still need to support the old way of customizing
+ * localized zone names, so we keep this field for the purpose.
+ */
+ UnicodeString **fZoneStrings; // Zone string array set by setZoneStrings
+ UnicodeString **fLocaleZoneStrings; // Zone string array created by the locale
+ int32_t fZoneStringsRowCount;
+ int32_t fZoneStringsColCount;
+
+ Locale fZSFLocale; // Locale used for getting ZoneStringFormat
+
+ /**
+ * String used for localized GMT. For example, "GMT"
+ */
+ UnicodeString fGmtZero;
+
+ /**
+ * 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& 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);
+
+ /**
+ * 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-4.8.1/i18n/unicode/dtitvfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvfmt.h
new file mode 100644
index 00000000000..009c3b08317
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvfmt.h
@@ -0,0 +1,992 @@
+/********************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVFMT.H
+*
+*******************************************************************************
+*/
+
+#ifndef __DTITVFMT_H__
+#define __DTITVFMT_H__
+
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse date interval in a language-independent manner.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ucal.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtintrv.h"
+#include "unicode/dtitvinf.h"
+#include "unicode/dtptngen.h"
+
+U_NAMESPACE_BEGIN
+
+
+
+/**
+ * DateIntervalFormat is a class for formatting and parsing date
+ * intervals in a language-independent manner.
+ * Only formatting is supported, parsing is not supported.
+ *
+ * <P>
+ * Date interval means from one date to another date,
+ * for example, from "Jan 11, 2008" to "Jan 18, 2008".
+ * We introduced class DateInterval to represent it.
+ * DateInterval is a pair of UDate, which is
+ * the standard milliseconds since 24:00 GMT, Jan 1, 1970.
+ *
+ * <P>
+ * DateIntervalFormat formats a DateInterval into
+ * text as compactly as possible.
+ * For example, the date interval format from "Jan 11, 2008" to "Jan 18,. 2008"
+ * is "Jan 11-18, 2008" for English.
+ * And it parses text into DateInterval,
+ * although initially, parsing is not supported.
+ *
+ * <P>
+ * There is no structural information in date time patterns.
+ * For any punctuations and string literals inside a date time pattern,
+ * we do not know whether it is just a separator, or a prefix, or a suffix.
+ * Without such information, so, it is difficult to generate a sub-pattern
+ * (or super-pattern) by algorithm.
+ * So, formatting a DateInterval is pattern-driven. It is very
+ * similar to formatting in SimpleDateFormat.
+ * We introduce class DateIntervalInfo to save date interval
+ * patterns, similar to date time pattern in SimpleDateFormat.
+ *
+ * <P>
+ * Logically, the interval patterns are mappings
+ * from (skeleton, the_largest_different_calendar_field)
+ * to (date_interval_pattern).
+ *
+ * <P>
+ * A skeleton
+ * <ol>
+ * <li>
+ * only keeps the field pattern letter and ignores all other parts
+ * in a pattern, such as space, punctuations, and string literals.
+ * </li>
+ * <li>
+ * hides the order of fields.
+ * </li>
+ * <li>
+ * might hide a field's pattern letter length.
+ * </li>
+ * </ol>
+ *
+ * For those non-digit calendar fields, the pattern letter length is
+ * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
+ * and the field's pattern letter length is honored.
+ *
+ * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
+ * the field pattern length is ignored and the best match, which is defined
+ * in date time patterns, will be returned without honor the field pattern
+ * letter length in skeleton.
+ *
+ * <P>
+ * The calendar fields we support for interval formatting are:
+ * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
+ * Those calendar fields can be defined in the following order:
+ * year > month > date > hour (in day) > minute
+ *
+ * The largest different calendar fields between 2 calendars is the
+ * first different calendar field in above order.
+ *
+ * For example: the largest different calendar fields between "Jan 10, 2007"
+ * and "Feb 20, 2008" is year.
+ *
+ * <P>
+ * For other calendar fields, the compact interval formatting is not
+ * supported. And the interval format will be fall back to fall-back
+ * patterns, which is mostly "{date0} - {date1}".
+ *
+ * <P>
+ * There is a set of pre-defined static skeleton strings.
+ * There are pre-defined interval patterns for those pre-defined skeletons
+ * in locales' resource files.
+ * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is &quot;yMMMd&quot;,
+ * in en_US, if the largest different calendar field between date1 and date2
+ * is &quot;year&quot;, the date interval pattern is &quot;MMM d, yyyy - MMM d, yyyy&quot;,
+ * such as &quot;Jan 10, 2007 - Jan 10, 2008&quot;.
+ * If the largest different calendar field between date1 and date2 is &quot;month&quot;,
+ * the date interval pattern is &quot;MMM d - MMM d, yyyy&quot;,
+ * such as &quot;Jan 10 - Feb 10, 2007&quot;.
+ * If the largest different calendar field between date1 and date2 is &quot;day&quot;,
+ * the date interval pattern is &quot;MMM d-d, yyyy&quot;, such as &quot;Jan 10-20, 2007&quot;.
+ *
+ * For date skeleton, the interval patterns when year, or month, or date is
+ * different are defined in resource files.
+ * For time skeleton, the interval patterns when am/pm, or hour, or minute is
+ * different are defined in resource files.
+ *
+ * <P>
+ * If a skeleton is not found in a locale's DateIntervalInfo, which means
+ * the interval patterns for the skeleton is not defined in resource file,
+ * the interval pattern will falls back to the interval "fallback" pattern
+ * defined in resource file.
+ * If the interval "fallback" pattern is not defined, the default fall-back
+ * is "{date0} - {data1}".
+ *
+ * <P>
+ * For the combination of date and time,
+ * The rule to generate interval patterns are:
+ * <ol>
+ * <li>
+ * when the year, month, or day differs, falls back to fall-back
+ * interval pattern, which mostly is the concatenate the two original
+ * expressions with a separator between,
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 11, 2007 10:10am" is
+ * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
+ * </li>
+ * <li>
+ * otherwise, present the date followed by the range expression
+ * for the time.
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 10, 2007 11:10am" is "Jan 10, 2007 10:10 am - 11:10am"
+ * </li>
+ * </ol>
+ *
+ *
+ * <P>
+ * If two dates are the same, the interval pattern is the single date pattern.
+ * For example, interval pattern from "Jan 10, 2007" to "Jan 10, 2007" is
+ * "Jan 10, 2007".
+ *
+ * Or if the presenting fields between 2 dates have the exact same values,
+ * the interval pattern is the single date pattern.
+ * For example, if user only requests year and month,
+ * the interval pattern from "Jan 10, 2007" to "Jan 20, 2007" is "Jan 2007".
+ *
+ * <P>
+ * DateIntervalFormat needs the following information for correct
+ * formatting: time zone, calendar type, pattern, date format symbols,
+ * and date interval patterns.
+ * It can be instantiated in 2 ways:
+ * <ol>
+ * <li>
+ * create an instance using default or given locale plus given skeleton.
+ * Users are encouraged to created date interval formatter this way and
+ * to use the pre-defined skeleton macros, such as
+ * UDAT_YEAR_NUM_MONTH, which consists the calendar fields and
+ * the format style.
+ * </li>
+ * <li>
+ * create an instance using default or given locale plus given skeleton
+ * plus a given DateIntervalInfo.
+ * This factory method is for powerful users who want to provide their own
+ * interval patterns.
+ * Locale provides the timezone, calendar, and format symbols information.
+ * Local plus skeleton provides full pattern information.
+ * DateIntervalInfo provides the date interval patterns.
+ * </li>
+ * </ol>
+ *
+ * <P>
+ * For the calendar field pattern letter, such as G, y, M, d, a, h, H, m, s etc.
+ * DateIntervalFormat uses the same syntax as that of
+ * DateTime format.
+ *
+ * <P>
+ * Code Sample: general usage
+ * <pre>
+ * \code
+ * // the date interval object which the DateIntervalFormat formats on
+ * // and parses into
+ * DateInterval* dtInterval = new DateInterval(1000*3600*24, 1000*3600*24*2);
+ * UErrorCode status = U_ZERO_ERROR;
+ * DateIntervalFormat* dtIntervalFmt = DateIntervalFormat::createInstance(
+ * UDAT_YEAR_MONTH_DAY,
+ * Locale("en", "GB", ""), status);
+ * UnicodeUnicodeString dateIntervalString;
+ * FieldPosition pos = 0;
+ * // formatting
+ * dtIntervalFmt->format(dtInterval, dateIntervalUnicodeString, pos, status);
+ * delete dtIntervalFmt;
+ * \endcode
+ * </pre>
+ */
+
+class U_I18N_API DateIntervalFormat : public Format {
+public:
+
+ /**
+ * Construct a DateIntervalFormat from skeleton and the default locale.
+ *
+ * This is a convenient override of
+ * createInstance(const UnicodeString& skeleton, const Locale& locale,
+ * UErrorCode&)
+ * with the value of locale as default locale.
+ *
+ * @param skeleton the skeleton on which interval format based.
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateIntervalFormat from skeleton and a given locale.
+ * <P>
+ * In this factory method,
+ * the date interval pattern information is load from resource files.
+ * Users are encouraged to created date interval formatter this way and
+ * to use the pre-defined skeleton macros.
+ *
+ * <P>
+ * There are pre-defined skeletons (defined in udate.h) having predefined
+ * interval patterns in resource files.
+ * Users are encouraged to use those macros.
+ * For example:
+ * DateIntervalFormat::createInstance(UDAT_MONTH_DAY, status)
+ *
+ * The given Locale provides the interval patterns.
+ * For example, for en_GB, if skeleton is UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY,
+ * which is "yMMMEEEd",
+ * the interval patterns defined in resource file to above skeleton are:
+ * "EEE, d MMM, yyyy - EEE, d MMM, yyyy" for year differs,
+ * "EEE, d MMM - EEE, d MMM, yyyy" for month differs,
+ * "EEE, d - EEE, d MMM, yyyy" for day differs,
+ * @param skeleton the skeleton on which the interval format is based.
+ * @param locale the given locale
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ const Locale& locale,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateIntervalFormat from skeleton
+ * DateIntervalInfo, and default locale.
+ *
+ * This is a convenient override of
+ * createInstance(const UnicodeString& skeleton, const Locale& locale,
+ * const DateIntervalInfo& dtitvinf, UErrorCode&)
+ * with the locale value as default locale.
+ *
+ * @param skeleton the skeleton on which interval format based.
+ * @param dtitvinf the DateIntervalInfo object.
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateIntervalFormat from skeleton
+ * a DateIntervalInfo, and the given locale.
+ *
+ * <P>
+ * In this factory method, user provides its own date interval pattern
+ * information, instead of using those pre-defined data in resource file.
+ * This factory method is for powerful users who want to provide their own
+ * interval patterns.
+ * <P>
+ * There are pre-defined skeletons (defined in udate.h) having predefined
+ * interval patterns in resource files.
+ * Users are encouraged to use those macros.
+ * For example:
+ * DateIntervalFormat::createInstance(UDAT_MONTH_DAY, status)
+ *
+ * The DateIntervalInfo provides the interval patterns.
+ * and the DateIntervalInfo ownership remains to the caller.
+ *
+ * User are encouraged to set default interval pattern in DateIntervalInfo
+ * as well, if they want to set other interval patterns ( instead of
+ * reading the interval patterns from resource files).
+ * When the corresponding interval pattern for a largest calendar different
+ * field is not found ( if user not set it ), interval format fallback to
+ * the default interval pattern.
+ * If user does not provide default interval pattern, it fallback to
+ * "{date0} - {date1}"
+ *
+ * @param skeleton the skeleton on which interval format based.
+ * @param locale the given locale
+ * @param dtitvinf the DateIntervalInfo object.
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ const Locale& locale,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status);
+
+ /**
+ * Destructor.
+ * @stable ICU 4.0
+ */
+ virtual ~DateIntervalFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @stable ICU 4.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 4.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Return true if the given Format objects are not 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 not semantically equal.
+ * @stable ICU 4.0
+ */
+ UBool operator!=(const Format& other) const;
+
+
+ using Format::format;
+
+ /**
+ * Format an object to produce a string. This method handles Formattable
+ * objects with a DateInterval type.
+ * If a the Formattable object type is not a DateInterval,
+ * then it returns a failing UErrorCode.
+ *
+ * @param obj The object to format.
+ * Must be a DateInterval.
+ * @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 status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const ;
+
+
+
+ /**
+ * Format a DateInterval to produce a string.
+ *
+ * @param dtInterval DateInterval to be formatted.
+ * @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 status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.0
+ */
+ UnicodeString& format(const DateInterval* dtInterval,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const ;
+
+
+ /**
+ * Format 2 Calendars to produce a string.
+ *
+ * Note: "fromCalendar" and "toCalendar" are not const,
+ * since calendar is not const in SimpleDateFormat::format(Calendar&),
+ *
+ * @param fromCalendar calendar set to the from date in date interval
+ * to be formatted into date interval string
+ * @param toCalendar calendar set to the to date in date interval
+ * to be formatted into date interval string
+ * @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 status Output param filled with success/failure status.
+ * Caller needs to make sure it is SUCCESS
+ * at the function entrance
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.0
+ */
+ UnicodeString& format(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const ;
+
+ /**
+ * Date interval parsing is not supported. Please do not use.
+ * <P>
+ * This method should handle parsing of
+ * date time interval strings into Formattable objects with
+ * DateInterval type, which is a pair of UDate.
+ * <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. Since no parsing
+ * is supported, upon return this param is unchanged.
+ * @return A newly created Formattable* object, or NULL
+ * on failure. The caller owns this and should
+ * delete it when done.
+ * @internal ICU 4.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const;
+
+
+ /**
+ * Gets the date time interval patterns.
+ * @return the date time interval patterns associated with
+ * this date interval formatter.
+ * @stable ICU 4.0
+ */
+ const DateIntervalInfo* getDateIntervalInfo(void) const;
+
+
+ /**
+ * Set the date time interval patterns.
+ * @param newIntervalPatterns the given interval patterns to copy.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ void setDateIntervalInfo(const DateIntervalInfo& newIntervalPatterns,
+ UErrorCode& status);
+
+
+ /**
+ * Gets the date formatter
+ * @return the date formatter associated with this date interval formatter.
+ * @stable ICU 4.0
+ */
+ const DateFormat* getDateFormat(void) const;
+
+ /**
+ * Returns a reference to the TimeZone used by this DateIntervalFormat's calendar.
+ * @return the time zone associated with the calendar of DateIntervalFormat.
+ * @draft ICU 4.8
+ */
+ virtual const TimeZone& getTimeZone(void) const;
+
+ /**
+ * Sets the time zone for the calendar used by this DateIntervalFormat 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 4.8
+ */
+ virtual void adoptTimeZone(TimeZone* zoneToAdopt);
+
+ /**
+ * Sets the time zone for the calendar used by this DateIntervalFormat object.
+ * @param zone the new time zone.
+ * @draft ICU 4.8
+ */
+ 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.
+ * @stable ICU 4.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 4.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+protected:
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.0
+ */
+ DateIntervalFormat(const DateIntervalFormat&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 4.0
+ */
+ DateIntervalFormat& operator=(const DateIntervalFormat&);
+
+private:
+
+ /*
+ * This is for ICU internal use only. Please do not use.
+ * Save the interval pattern information.
+ * Interval pattern consists of 2 single date patterns and the separator.
+ * For example, interval pattern "MMM d - MMM d, yyyy" consists
+ * a single date pattern "MMM d", another single date pattern "MMM d, yyyy",
+ * and a separator "-".
+ * The pattern is divided into 2 parts. For above example,
+ * the first part is "MMM d - ", and the second part is "MMM d, yyyy".
+ * Also, the first date appears in an interval pattern could be
+ * the earlier date or the later date.
+ * And such information is saved in the interval pattern as well.
+ * @internal ICU 4.0
+ */
+ struct PatternInfo {
+ UnicodeString firstPart;
+ UnicodeString secondPart;
+ /**
+ * Whether the first date in interval pattern is later date or not.
+ * Fallback format set the default ordering.
+ * And for a particular interval pattern, the order can be
+ * overriden by prefixing the interval pattern with "latestFirst:" or
+ * "earliestFirst:"
+ * For example, given 2 date, Jan 10, 2007 to Feb 10, 2007.
+ * if the fallback format is "{0} - {1}",
+ * and the pattern is "d MMM - d MMM yyyy", the interval format is
+ * "10 Jan - 10 Feb, 2007".
+ * If the pattern is "latestFirst:d MMM - d MMM yyyy",
+ * the interval format is "10 Feb - 10 Jan, 2007"
+ */
+ UBool laterDateFirst;
+ };
+
+
+ /**
+ * default constructor
+ * @internal ICU 4.0
+ */
+ DateIntervalFormat();
+
+ /**
+ * Construct a DateIntervalFormat from DateFormat,
+ * a DateIntervalInfo, and skeleton.
+ * DateFormat provides the timezone, calendar,
+ * full pattern, and date format symbols information.
+ * It should be a SimpleDateFormat object which
+ * has a pattern in it.
+ * the DateIntervalInfo provides the interval patterns.
+ *
+ * Note: the DateIntervalFormat takes ownership of both
+ * DateFormat and DateIntervalInfo objects.
+ * Caller should not delete them.
+ *
+ * @param locale the locale of this date interval formatter.
+ * @param dtItvInfo the DateIntervalInfo object to be adopted.
+ * @param skeleton the skeleton of the date formatter
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ DateIntervalFormat(const Locale& locale, DateIntervalInfo* dtItvInfo,
+ const UnicodeString* skeleton, UErrorCode& status);
+
+
+ /**
+ * Construct a DateIntervalFormat from DateFormat
+ * and a DateIntervalInfo.
+ *
+ * It is a wrapper of the constructor.
+ *
+ * @param locale the locale of this date interval formatter.
+ * @param dtitvinf the DateIntervalInfo object to be adopted.
+ * @param skeleton the skeleton of this formatter.
+ * @param status Output param set to success/failure code.
+ * @return a date time interval formatter which the caller owns.
+ * @internal ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 create(const Locale& locale,
+ DateIntervalInfo* dtitvinf,
+ const UnicodeString* skeleton,
+ UErrorCode& status);
+
+ /**
+ * Create a simple date/time formatter from skeleton, given locale,
+ * and date time pattern generator.
+ *
+ * @param skeleton the skeleton on which date format based.
+ * @param locale the given locale.
+ * @param dtpng the date time pattern generator.
+ * @param status Output param to be set to success/failure code.
+ * If it is failure, the returned date formatter will
+ * be NULL.
+ * @return a simple date formatter which the caller owns.
+ * @internal ICU 4.0
+ */
+ static SimpleDateFormat* U_EXPORT2 createSDFPatternInstance(
+ const UnicodeString& skeleton,
+ const Locale& locale,
+ DateTimePatternGenerator* dtpng,
+ UErrorCode& status);
+
+
+ /**
+ * Below are for generating interval patterns local to the formatter
+ */
+
+
+ /**
+ * Format 2 Calendars using fall-back interval pattern
+ *
+ * The full pattern used in this fall-back format is the
+ * full pattern of the date formatter.
+ *
+ * @param fromCalendar calendar set to the from date in date interval
+ * to be formatted into date interval string
+ * @param toCalendar calendar set to the to date in date interval
+ * to be formatted into date interval string
+ * @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.
+ * @internal ICU 4.0
+ */
+ UnicodeString& fallbackFormat(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+
+
+ /**
+ * Initialize interval patterns locale to this formatter
+ *
+ * This code is a bit complicated since
+ * 1. the interval patterns saved in resource bundle files are interval
+ * patterns based on date or time only.
+ * It does not have interval patterns based on both date and time.
+ * Interval patterns on both date and time are algorithm generated.
+ *
+ * For example, it has interval patterns on skeleton "dMy" and "hm",
+ * but it does not have interval patterns on skeleton "dMyhm".
+ *
+ * The rule to generate interval patterns for both date and time skeleton are
+ * 1) when the year, month, or day differs, concatenate the two original
+ * expressions with a separator between,
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 11, 2007 10:10am" is
+ * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
+ *
+ * 2) otherwise, present the date followed by the range expression
+ * for the time.
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 10, 2007 11:10am" is
+ * "Jan 10, 2007 10:10 am - 11:10am"
+ *
+ * 2. even a pattern does not request a certain calendar field,
+ * the interval pattern needs to include such field if such fields are
+ * different between 2 dates.
+ * For example, a pattern/skeleton is "hm", but the interval pattern
+ * includes year, month, and date when year, month, and date differs.
+ *
+ *
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void initializePattern(UErrorCode& status);
+
+
+
+ /**
+ * Set fall back interval pattern given a calendar field,
+ * a skeleton, and a date time pattern generator.
+ * @param field the largest different calendar field
+ * @param skeleton a skeleton
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void setFallbackPattern(UCalendarDateFields field,
+ const UnicodeString& skeleton,
+ UErrorCode& status);
+
+
+
+ /**
+ * get separated date and time skeleton from a combined skeleton.
+ *
+ * The difference between date skeleton and normalizedDateSkeleton are:
+ * 1. both 'y' and 'd' are appeared only once in normalizeDateSkeleton
+ * 2. 'E' and 'EE' are normalized into 'EEE'
+ * 3. 'MM' is normalized into 'M'
+ *
+ ** the difference between time skeleton and normalizedTimeSkeleton are:
+ * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
+ * 2. 'a' is omitted in normalized time skeleton.
+ * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized time
+ * skeleton
+ *
+ *
+ * @param skeleton given combined skeleton.
+ * @param date Output parameter for date only skeleton.
+ * @param normalizedDate Output parameter for normalized date only
+ *
+ * @param time Output parameter for time only skeleton.
+ * @param normalizedTime Output parameter for normalized time only
+ * skeleton.
+ *
+ * @internal ICU 4.0
+ */
+ static void U_EXPORT2 getDateTimeSkeleton(const UnicodeString& skeleton,
+ UnicodeString& date,
+ UnicodeString& normalizedDate,
+ UnicodeString& time,
+ UnicodeString& normalizedTime);
+
+
+
+ /**
+ * Generate date or time interval pattern from resource,
+ * and set them into the interval pattern locale to this formatter.
+ *
+ * It needs to handle the following:
+ * 1. need to adjust field width.
+ * For example, the interval patterns saved in DateIntervalInfo
+ * includes "dMMMy", but not "dMMMMy".
+ * Need to get interval patterns for dMMMMy from dMMMy.
+ * Another example, the interval patterns saved in DateIntervalInfo
+ * includes "hmv", but not "hmz".
+ * Need to get interval patterns for "hmz' from 'hmv'
+ *
+ * 2. there might be no pattern for 'y' differ for skeleton "Md",
+ * in order to get interval patterns for 'y' differ,
+ * need to look for it from skeleton 'yMd'
+ *
+ * @param dateSkeleton normalized date skeleton
+ * @param timeSkeleton normalized time skeleton
+ * @return whether the resource is found for the skeleton.
+ * TRUE if interval pattern found for the skeleton,
+ * FALSE otherwise.
+ * @internal ICU 4.0
+ */
+ UBool setSeparateDateTimePtn(const UnicodeString& dateSkeleton,
+ const UnicodeString& timeSkeleton);
+
+
+
+
+ /**
+ * Generate interval pattern from existing resource
+ *
+ * It not only save the interval patterns,
+ * but also return the extended skeleton and its best match skeleton.
+ *
+ * @param field largest different calendar field
+ * @param skeleton skeleton
+ * @param bestSkeleton the best match skeleton which has interval pattern
+ * defined in resource
+ * @param differenceInfo the difference between skeleton and best skeleton
+ * 0 means the best matched skeleton is the same as input skeleton
+ * 1 means the fields are the same, but field width are different
+ * 2 means the only difference between fields are v/z,
+ * -1 means there are other fields difference
+ *
+ * @param extendedSkeleton extended skeleton
+ * @param extendedBestSkeleton extended best match skeleton
+ * @return whether the interval pattern is found
+ * through extending skeleton or not.
+ * TRUE if interval pattern is found by
+ * extending skeleton, FALSE otherwise.
+ * @internal ICU 4.0
+ */
+ UBool setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString* skeleton,
+ const UnicodeString* bestSkeleton,
+ int8_t differenceInfo,
+ UnicodeString* extendedSkeleton = NULL,
+ UnicodeString* extendedBestSkeleton = NULL);
+
+ /**
+ * Adjust field width in best match interval pattern to match
+ * the field width in input skeleton.
+ *
+ * TODO (xji) make a general solution
+ * The adjusting rule can be:
+ * 1. always adjust
+ * 2. never adjust
+ * 3. default adjust, which means adjust according to the following rules
+ * 3.1 always adjust string, such as MMM and MMMM
+ * 3.2 never adjust between string and numeric, such as MM and MMM
+ * 3.3 always adjust year
+ * 3.4 do not adjust 'd', 'h', or 'm' if h presents
+ * 3.5 do not adjust 'M' if it is numeric(?)
+ *
+ * Since date interval format is well-formed format,
+ * date and time skeletons are normalized previously,
+ * till this stage, the adjust here is only "adjust strings, such as MMM
+ * and MMMM, EEE and EEEE.
+ *
+ * @param inputSkeleton the input skeleton
+ * @param bestMatchSkeleton the best match skeleton
+ * @param bestMatchIntervalPattern the best match interval pattern
+ * @param differenceInfo the difference between 2 skeletons
+ * 1 means only field width differs
+ * 2 means v/z exchange
+ * @param adjustedIntervalPattern adjusted interval pattern
+ * @internal ICU 4.0
+ */
+ static void U_EXPORT2 adjustFieldWidth(
+ const UnicodeString& inputSkeleton,
+ const UnicodeString& bestMatchSkeleton,
+ const UnicodeString& bestMatchIntervalPattern,
+ int8_t differenceInfo,
+ UnicodeString& adjustedIntervalPattern);
+
+ /**
+ * Concat a single date pattern with a time interval pattern,
+ * set it into the intervalPatterns, while field is time field.
+ * This is used to handle time interval patterns on skeleton with
+ * both time and date. Present the date followed by
+ * the range expression for the time.
+ * @param format date and time format
+ * @param formatLen format string length
+ * @param datePattern date pattern
+ * @param field time calendar field: AM_PM, HOUR, MINUTE
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void concatSingleDate2TimeInterval(const UChar* format,
+ int32_t formatLen,
+ const UnicodeString& datePattern,
+ UCalendarDateFields field,
+ UErrorCode& status);
+
+ /**
+ * check whether a calendar field present in a skeleton.
+ * @param field calendar field need to check
+ * @param skeleton given skeleton on which to check the calendar field
+ * @return true if field present in a skeleton.
+ * @internal ICU 4.0
+ */
+ static UBool U_EXPORT2 fieldExistsInSkeleton(UCalendarDateFields field,
+ const UnicodeString& skeleton);
+
+
+ /**
+ * Split interval patterns into 2 part.
+ * @param intervalPattern interval pattern
+ * @return the index in interval pattern which split the pattern into 2 part
+ * @internal ICU 4.0
+ */
+ static int32_t U_EXPORT2 splitPatternInto2Part(const UnicodeString& intervalPattern);
+
+
+ /**
+ * Break interval patterns as 2 part and save them into pattern info.
+ * @param field calendar field
+ * @param intervalPattern interval pattern
+ * @internal ICU 4.0
+ */
+ void setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern);
+
+
+ /**
+ * Break interval patterns as 2 part and save them into pattern info.
+ * @param field calendar field
+ * @param intervalPattern interval pattern
+ * @param laterDateFirst whether later date appear first in interval pattern
+ * @internal ICU 4.0
+ */
+ void setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern,
+ UBool laterDateFirst);
+
+
+ /**
+ * Set pattern information.
+ *
+ * @param field calendar field
+ * @param firstPart the first part in interval pattern
+ * @param secondPart the second part in interval pattern
+ * @param laterDateFirst whether the first date in intervalPattern
+ * is earlier date or later date
+ * @internal ICU 4.0
+ */
+ void setPatternInfo(UCalendarDateFields field,
+ const UnicodeString* firstPart,
+ const UnicodeString* secondPart,
+ UBool laterDateFirst);
+
+
+ // from calendar field to pattern letter
+ static const UChar fgCalendarFieldToPatternLetter[];
+
+
+ /**
+ * The interval patterns for this locale.
+ */
+ DateIntervalInfo* fInfo;
+
+ /**
+ * The DateFormat object used to format single pattern
+ */
+ SimpleDateFormat* fDateFormat;
+
+ /**
+ * The 2 calendars with the from and to date.
+ * could re-use the calendar in fDateFormat,
+ * but keeping 2 calendars make it clear and clean.
+ */
+ Calendar* fFromCalendar;
+ Calendar* fToCalendar;
+
+ /**
+ * Date time pattern generator
+ */
+ DateTimePatternGenerator* fDtpng;
+
+ /**
+ * Following are interval information relavent (locale) to this formatter.
+ */
+ UnicodeString fSkeleton;
+ PatternInfo fIntervalPatterns[DateIntervalInfo::kIPI_MAX_INDEX];
+};
+
+inline UBool
+DateIntervalFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DTITVFMT_H__
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvinf.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvinf.h
new file mode 100644
index 00000000000..f6513a2147b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtitvinf.h
@@ -0,0 +1,527 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ *
+ * File DTITVINF.H
+ *
+ *******************************************************************************
+ */
+
+#ifndef __DTITVINF_H__
+#define __DTITVINF_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Date/Time interval patterns for formatting date/time interval
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udat.h"
+#include "unicode/locid.h"
+#include "unicode/ucal.h"
+#include "unicode/dtptngen.h"
+//#include "dtitv_impl.h"
+
+/**
+ * @internal ICU 4.0
+ */
+
+union UHashTok;
+
+
+U_NAMESPACE_BEGIN
+
+/**
+ * DateIntervalInfo is a public class for encapsulating localizable
+ * date time interval patterns. It is used by DateIntervalFormat.
+ *
+ * <P>
+ * For most users, ordinary use of DateIntervalFormat does not need to create
+ * DateIntervalInfo object directly.
+ * DateIntervalFormat will take care of it when creating a date interval
+ * formatter when user pass in skeleton and locale.
+ *
+ * <P>
+ * For power users, who want to create their own date interval patterns,
+ * or want to re-set date interval patterns, they could do so by
+ * directly creating DateIntervalInfo and manupulating it.
+ *
+ * <P>
+ * Logically, the interval patterns are mappings
+ * from (skeleton, the_largest_different_calendar_field)
+ * to (date_interval_pattern).
+ *
+ * <P>
+ * A skeleton
+ * <ol>
+ * <li>
+ * only keeps the field pattern letter and ignores all other parts
+ * in a pattern, such as space, punctuations, and string literals.
+ * <li>
+ * hides the order of fields.
+ * <li>
+ * might hide a field's pattern letter length.
+ *
+ * For those non-digit calendar fields, the pattern letter length is
+ * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
+ * and the field's pattern letter length is honored.
+ *
+ * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
+ * the field pattern length is ignored and the best match, which is defined
+ * in date time patterns, will be returned without honor the field pattern
+ * letter length in skeleton.
+ * </ol>
+ *
+ * <P>
+ * The calendar fields we support for interval formatting are:
+ * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
+ * Those calendar fields can be defined in the following order:
+ * year > month > date > am-pm > hour > minute
+ *
+ * The largest different calendar fields between 2 calendars is the
+ * first different calendar field in above order.
+ *
+ * For example: the largest different calendar fields between &quot;Jan 10, 2007&quot;
+ * and &quot;Feb 20, 2008&quot; is year.
+ *
+ * <P>
+ * There is a set of pre-defined static skeleton strings.
+ * There are pre-defined interval patterns for those pre-defined skeletons
+ * in locales' resource files.
+ * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is &quot;yMMMd&quot;,
+ * in en_US, if the largest different calendar field between date1 and date2
+ * is &quot;year&quot;, the date interval pattern is &quot;MMM d, yyyy - MMM d, yyyy&quot;,
+ * such as &quot;Jan 10, 2007 - Jan 10, 2008&quot;.
+ * If the largest different calendar field between date1 and date2 is &quot;month&quot;,
+ * the date interval pattern is &quot;MMM d - MMM d, yyyy&quot;,
+ * such as &quot;Jan 10 - Feb 10, 2007&quot;.
+ * If the largest different calendar field between date1 and date2 is &quot;day&quot;,
+ * the date interval pattern is &quot;MMM d-d, yyyy&quot;, such as &quot;Jan 10-20, 2007&quot;.
+ *
+ * For date skeleton, the interval patterns when year, or month, or date is
+ * different are defined in resource files.
+ * For time skeleton, the interval patterns when am/pm, or hour, or minute is
+ * different are defined in resource files.
+ *
+ *
+ * <P>
+ * There are 2 dates in interval pattern. For most locales, the first date
+ * in an interval pattern is the earlier date. There might be a locale in which
+ * the first date in an interval pattern is the later date.
+ * We use fallback format for the default order for the locale.
+ * For example, if the fallback format is &quot;{0} - {1}&quot;, it means
+ * the first date in the interval pattern for this locale is earlier date.
+ * If the fallback format is &quot;{1} - {0}&quot;, it means the first date is the
+ * later date.
+ * For a particular interval pattern, the default order can be overriden
+ * by prefixing &quot;latestFirst:&quot; or &quot;earliestFirst:&quot; to the interval pattern.
+ * For example, if the fallback format is &quot;{0}-{1}&quot;,
+ * but for skeleton &quot;yMMMd&quot;, the interval pattern when day is different is
+ * &quot;latestFirst:d-d MMM yy&quot;, it means by default, the first date in interval
+ * pattern is the earlier date. But for skeleton &quot;yMMMd&quot;, when day is different,
+ * the first date in &quot;d-d MMM yy&quot; is the later date.
+ *
+ * <P>
+ * The recommended way to create a DateIntervalFormat object is to pass in
+ * the locale.
+ * By using a Locale parameter, the DateIntervalFormat object is
+ * initialized with the pre-defined interval patterns for a given or
+ * default locale.
+ * <P>
+ * Users can also create DateIntervalFormat object
+ * by supplying their own interval patterns.
+ * It provides flexibility for power users.
+ *
+ * <P>
+ * After a DateIntervalInfo object is created, clients may modify
+ * the interval patterns using setIntervalPattern function as so desired.
+ * Currently, users can only set interval patterns when the following
+ * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
+ * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
+ * Interval patterns when other calendar fields are different is not supported.
+ * <P>
+ * DateIntervalInfo objects are cloneable.
+ * When clients obtain a DateIntervalInfo object,
+ * they can feel free to modify it as necessary.
+ * <P>
+ * DateIntervalInfo are not expected to be subclassed.
+ * Data for a calendar is loaded out of resource bundles.
+ * Through ICU 4.4, date interval patterns are only supported in the Gregorian
+ * calendar; non-Gregorian calendars are supported from ICU 4.4.1.
+ * @stable ICU 4.0
+**/
+
+class U_I18N_API DateIntervalInfo : public UObject {
+public:
+ /**
+ * Default constructor.
+ * It does not initialize any interval patterns except
+ * that it initialize default fall-back pattern as "{0} - {1}",
+ * which can be reset by setFallbackIntervalPattern().
+ * It should be followed by setFallbackIntervalPattern() and
+ * setIntervalPattern(),
+ * and is recommended to be used only for power users who
+ * wants to create their own interval patterns and use them to create
+ * date interval formatter.
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ DateIntervalInfo(UErrorCode& status);
+
+
+ /**
+ * Construct DateIntervalInfo for the given locale,
+ * @param locale the interval patterns are loaded from the appropriate calendar
+ * data (specified calendar or default calendar) in this locale.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ DateIntervalInfo(const Locale& locale, UErrorCode& status);
+
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.0
+ */
+ DateIntervalInfo(const DateIntervalInfo&);
+
+ /**
+ * Assignment operator
+ * @stable ICU 4.0
+ */
+ DateIntervalInfo& operator=(const DateIntervalInfo&);
+
+ /**
+ * Clone this object polymorphically.
+ * The caller owns the result and should delete it when done.
+ * @return a copy of the object
+ * @stable ICU 4.0
+ */
+ virtual DateIntervalInfo* clone(void) const;
+
+ /**
+ * Destructor.
+ * It is virtual to be safe, but it is not designed to be subclassed.
+ * @stable ICU 4.0
+ */
+ virtual ~DateIntervalInfo();
+
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the DateIntervalInfo object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @stable ICU 4.0
+ */
+ virtual UBool operator==(const DateIntervalInfo& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the DateIntervalInfo object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @stable ICU 4.0
+ */
+ UBool operator!=(const DateIntervalInfo& other) const;
+
+
+
+ /**
+ * Provides a way for client to build interval patterns.
+ * User could construct DateIntervalInfo by providing a list of skeletons
+ * and their patterns.
+ * <P>
+ * For example:
+ * <pre>
+ * UErrorCode status = U_ZERO_ERROR;
+ * DateIntervalInfo dIntervalInfo = new DateIntervalInfo();
+ * dIntervalInfo->setFallbackIntervalPattern("{0} ~ {1}");
+ * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status);
+ * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_MONTH, "'from' yyyy MMM d 'to' MMM d", status);
+ * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_DAY, "yyyy MMM d-d", status, status);
+ * </pre>
+ *
+ * Restriction:
+ * Currently, users can only set interval patterns when the following
+ * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
+ * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
+ * Interval patterns when other calendar fields are different are
+ * not supported.
+ *
+ * @param skeleton the skeleton on which interval pattern based
+ * @param lrgDiffCalUnit the largest different calendar unit.
+ * @param intervalPattern the interval pattern on the largest different
+ * calendar unit.
+ * For example, if lrgDiffCalUnit is
+ * "year", the interval pattern for en_US when year
+ * is different could be "'from' yyyy 'to' yyyy".
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ void setIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status);
+
+ /**
+ * Get the interval pattern given skeleton and
+ * the largest different calendar field.
+ * @param skeleton the skeleton
+ * @param field the largest different calendar field
+ * @param result output param to receive the pattern
+ * @param status output param set to success/failure code on exit
+ * @return a reference to 'result'
+ * @stable ICU 4.0
+ */
+ UnicodeString& getIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields field,
+ UnicodeString& result,
+ UErrorCode& status) const;
+
+ /**
+ * Get the fallback interval pattern.
+ * @param result output param to receive the pattern
+ * @return a reference to 'result'
+ * @stable ICU 4.0
+ */
+ UnicodeString& getFallbackIntervalPattern(UnicodeString& result) const;
+
+
+ /**
+ * Re-set the fallback interval pattern.
+ *
+ * In construction, default fallback pattern is set as "{0} - {1}".
+ * And constructor taking locale as parameter will set the
+ * fallback pattern as what defined in the locale resource file.
+ *
+ * This method provides a way for user to replace the fallback pattern.
+ *
+ * @param fallbackPattern fall-back interval pattern.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ void setFallbackIntervalPattern(const UnicodeString& fallbackPattern,
+ UErrorCode& status);
+
+
+ /** Get default order -- whether the first date in pattern is later date
+ or not.
+ * return default date ordering in interval pattern. TRUE if the first date
+ * in pattern is later date, FALSE otherwise.
+ * @stable ICU 4.0
+ */
+ UBool getDefaultOrder() const;
+
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 4.0
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 4.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+
+private:
+ /**
+ * DateIntervalFormat will need access to
+ * getBestSkeleton(), parseSkeleton(), enum IntervalPatternIndex,
+ * and calendarFieldToPatternIndex().
+ *
+ * Instead of making above public,
+ * make DateIntervalFormat a friend of DateIntervalInfo.
+ */
+ friend class DateIntervalFormat;
+
+ /**
+ * Following is for saving the interval patterns.
+ * We only support interval patterns on
+ * ERA, YEAR, MONTH, DAY, AM_PM, HOUR, and MINUTE
+ */
+ enum IntervalPatternIndex
+ {
+ kIPI_ERA,
+ kIPI_YEAR,
+ kIPI_MONTH,
+ kIPI_DATE,
+ kIPI_AM_PM,
+ kIPI_HOUR,
+ kIPI_MINUTE,
+ kIPI_MAX_INDEX
+ };
+public:
+ /**
+ * Max index for stored interval patterns
+ * @internal ICU 4.4
+ */
+ enum {
+ kMaxIntervalPatternIndex = kIPI_MAX_INDEX
+ };
+private:
+
+
+ /**
+ * Initialize the DateIntervalInfo from locale
+ * @param locale the given locale.
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void initializeData(const Locale& locale, UErrorCode& status);
+
+
+ /* Set Interval pattern.
+ *
+ * It sets interval pattern into the hash map.
+ *
+ * @param skeleton skeleton on which the interval pattern based
+ * @param lrgDiffCalUnit the largest different calendar unit.
+ * @param intervalPattern the interval pattern on the largest different
+ * calendar unit.
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void setIntervalPatternInternally(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status);
+
+
+ /**given an input skeleton, get the best match skeleton
+ * which has pre-defined interval pattern in resource file.
+ * Also return the difference between the input skeleton
+ * and the best match skeleton.
+ *
+ * TODO (xji): set field weight or
+ * isolate the funtionality in DateTimePatternGenerator
+ * @param skeleton input skeleton
+ * @param bestMatchDistanceInfo the difference between input skeleton
+ * and best match skeleton.
+ * 0, if there is exact match for input skeleton
+ * 1, if there is only field width difference between
+ * the best match and the input skeleton
+ * 2, the only field difference is 'v' and 'z'
+ * -1, if there is calendar field difference between
+ * the best match and the input skeleton
+ * @return best match skeleton
+ * @internal ICU 4.0
+ */
+ const UnicodeString* getBestSkeleton(const UnicodeString& skeleton,
+ int8_t& bestMatchDistanceInfo) const;
+
+
+ /**
+ * Parse skeleton, save each field's width.
+ * It is used for looking for best match skeleton,
+ * and adjust pattern field width.
+ * @param skeleton skeleton to be parsed
+ * @param skeletonFieldWidth parsed skeleton field width
+ * @internal ICU 4.0
+ */
+ static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton,
+ int32_t* skeletonFieldWidth);
+
+
+ /**
+ * Check whether one field width is numeric while the other is string.
+ *
+ * TODO (xji): make it general
+ *
+ * @param fieldWidth one field width
+ * @param anotherFieldWidth another field width
+ * @param patternLetter pattern letter char
+ * @return true if one field width is numeric and the other is string,
+ * false otherwise.
+ * @internal ICU 4.0
+ */
+ static UBool U_EXPORT2 stringNumeric(int32_t fieldWidth,
+ int32_t anotherFieldWidth,
+ char patternLetter);
+
+
+ /**
+ * Convert calendar field to the interval pattern index in
+ * hash table.
+ *
+ * Since we only support the following calendar fields:
+ * ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK,
+ * AM_PM, HOUR, HOUR_OF_DAY, and MINUTE,
+ * We reserve only 4 interval patterns for a skeleton.
+ *
+ * @param field calendar field
+ * @param status output param set to success/failure code on exit
+ * @return interval pattern index in hash table
+ * @internal ICU 4.0
+ */
+ static IntervalPatternIndex U_EXPORT2 calendarFieldToIntervalIndex(
+ UCalendarDateFields field,
+ UErrorCode& status);
+
+
+ /**
+ * delete hash table (of type fIntervalPatterns).
+ *
+ * @param hTable hash table to be deleted
+ * @internal ICU 4.0
+ */
+ void deleteHash(Hashtable* hTable);
+
+
+ /**
+ * initialize hash table (of type fIntervalPatterns).
+ *
+ * @param status output param set to success/failure code on exit
+ * @return hash table initialized
+ * @internal ICU 4.0
+ */
+ Hashtable* initHash(UErrorCode& status);
+
+
+
+ /**
+ * copy hash table (of type fIntervalPatterns).
+ *
+ * @param source the source to copy from
+ * @param target the target to copy to
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
+
+
+ // data members
+ // fallback interval pattern
+ UnicodeString fFallbackIntervalPattern;
+ // default order
+ UBool fFirstDateInPtnIsLaterDate;
+
+ // HashMap<UnicodeString, UnicodeString[kIPI_MAX_INDEX]>
+ // HashMap( skeleton, pattern[largest_different_field] )
+ Hashtable* fIntervalPatterns;
+
+};// end class DateIntervalInfo
+
+
+inline UBool
+DateIntervalInfo::operator!=(const DateIntervalInfo& other) const {
+ return !operator==(other);
+}
+
+
+U_NAMESPACE_END
+
+#endif
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtptngen.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtptngen.h
new file mode 100644
index 00000000000..1a0f70bc844
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtptngen.h
@@ -0,0 +1,474 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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
+
+/**
+ * \file
+ * \brief C++ API: Date/Time Pattern Generator
+ */
+
+
+class Hashtable;
+class FormatParser;
+class DateTimeMatcher;
+class DistanceInfo;
+class PatternMap;
+class PtnSkeleton;
+
+/**
+ * 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>
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ static DateTimePatternGenerator* U_EXPORT2 createEmptyInstance(UErrorCode& status);
+
+ /**
+ * Destructor.
+ * @stable ICU 3.8
+ */
+ virtual ~DateTimePatternGenerator();
+
+ /**
+ * Clone DateTimePatternGenerator object. Clients are responsible for
+ * deleting the DateTimePatternGenerator object cloned.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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"
+ * @stable 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"
+ * @stable 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.
+ * @stable 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}"
+ * @stable 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
+ * @stable 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
+ * @stable 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
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ void setDateTimeFormat(const UnicodeString& dateTimeFormat);
+
+ /**
+ * Getter corresponding to setDateTimeFormat.
+ * @return DateTimeFormat.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ UnicodeString getBestPattern(const UnicodeString& skeleton, UErrorCode& status);
+
+
+ /**
+ * 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 options
+ * Options for forcing the length of specified fields in the
+ * returned pattern to match those in the skeleton (when this
+ * would not happen otherwise). For default behavior, use
+ * UDATPG_MATCH_NO_OPTIONS.
+ * @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.
+ * @stable ICU 4.4
+ */
+ UnicodeString getBestPattern(const UnicodeString& skeleton,
+ UDateTimePatternMatchOptions options,
+ 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.
+ * @stable ICU 3.8
+ */
+ UnicodeString replaceFieldTypes(const UnicodeString& pattern,
+ 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 options
+ * Options controlling whether the length of specified fields in the
+ * pattern are adjusted to match those in the skeleton (when this
+ * would not happen otherwise). For default behavior, use
+ * UDATPG_MATCH_NO_OPTIONS.
+ * @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.
+ * @stable ICU 4.4
+ */
+ UnicodeString replaceFieldTypes(const UnicodeString& pattern,
+ const UnicodeString& skeleton,
+ UDateTimePatternMatchOptions options,
+ 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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
+ * @stable ICU 3.8
+ */
+ void setDecimal(const UnicodeString& decimal);
+
+ /**
+ * Getter corresponding to setDecimal.
+ * @return UnicodeString corresponding to the decimal point
+ * @stable ICU 3.8
+ */
+ const UnicodeString& getDecimal() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 3.8
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+private:
+ /**
+ * Constructor.
+ * @stable ICU 3.8
+ */
+ DateTimePatternGenerator(UErrorCode & status);
+
+ /**
+ * Constructor.
+ * @stable ICU 3.8
+ */
+ DateTimePatternGenerator(const Locale& locale, UErrorCode & status);
+
+ /**
+ * Copy constructor.
+ * @param other DateTimePatternGenerator to copy
+ * @stable ICU 3.8
+ */
+ DateTimePatternGenerator(const DateTimePatternGenerator& other);
+
+ /**
+ * Default assignment operator.
+ * @param other DateTimePatternGenerator to copy
+ * @stable 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;
+ UnicodeString emptyString;
+ UChar fDefaultHourFormatChar;
+
+ void initData(const Locale &locale, UErrorCode &status);
+ void addCanonicalItems();
+ void addICUPatterns(const Locale& locale, UErrorCode& status);
+ void hackTimes(const UnicodeString& hackPattern, UErrorCode& status);
+ void addCLDRData(const Locale& locale, UErrorCode& status);
+ UDateTimePatternConflict addPatternWithSkeleton(const UnicodeString& pattern, const UnicodeString * skeletonToUse, UBool override, UnicodeString& conflictingPattern, UErrorCode& status);
+ 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, const PtnSkeleton** specifiedSkeletonPtr = 0);
+ UnicodeString adjustFieldTypes(const UnicodeString& pattern, const PtnSkeleton* specifiedSkeleton, UBool fixFractionalSeconds, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS);
+ UnicodeString getBestAppending(int32_t missingFields, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS);
+ int32_t getTopBitNumber(int32_t foundMask);
+ void setAvailableFormat(const UnicodeString &key, UErrorCode& status);
+ UBool isAvailableFormatSet(const UnicodeString &key) const;
+ void copyHashtable(Hashtable *other, UErrorCode &status);
+ UBool isCanonicalItem(const UnicodeString& item) const;
+} ;// end class DateTimePatternGenerator
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtrule.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtrule.h
new file mode 100644
index 00000000000..cb526a152ce
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/dtrule.h
@@ -0,0 +1,250 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, 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.
+ *
+ * @stable ICU 3.8
+ */
+class U_I18N_API DateTimeRule : public UObject {
+public:
+
+ /**
+ * Date rule type constants.
+ * @stable 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.
+ * @stable 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>.
+ * @stable 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>.
+ * @stable 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>.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ DateTimeRule(const DateTimeRule& source);
+
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ DateTimeRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ UBool operator!=(const DateTimeRule& that) const;
+
+ /**
+ * Gets the date rule type, such as <code>DOM</code>
+ * @return The date rule type.
+ * @stable 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>.
+ * @stable ICU 3.8
+ */
+ TimeRuleType getTimeRuleType(void) const;
+
+ /**
+ * Gets the rule month.
+ * @return The rule month.
+ * @stable 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
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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-4.8.1/i18n/unicode/fieldpos.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/fieldpos.h
new file mode 100644
index 00000000000..38a9576e782
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/fmtable.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/fmtable.h
new file mode 100644
index 00000000000..9cc423a7182
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/fmtable.h
@@ -0,0 +1,673 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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"
+#include "unicode/stringpiece.h"
+
+/**
+ * \file
+ * \brief C++ API: Formattable is a thin wrapper for primitive numeric types.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+class CharString;
+class DigitList;
+
+/**
+ * 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 of an appropriate numeric type from a
+ * a decimal number in string form. The Formattable will retain the
+ * full precision of the input in decimal format, even when it exceeds
+ * what can be represented by a double of int64_t.
+ *
+ * @param number the unformatted (not localized) string representation
+ * of the Decimal number.
+ * @param status the error code. Possible errors include U_INVALID_FORMAT_ERROR
+ * if the format of the string does not conform to that of a
+ * decimal number.
+ * @stable ICU 4.4
+ */
+ Formattable(const StringPiece &number, UErrorCode &status);
+
+ /**
+ * 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, kInt64 or kDecimalNumber.
+ * @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, int64 or Decimal Number then a 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 or kDecimalNumber, then a 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 a numeric
+ * type 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;
+
+ /**
+ * Returns a numeric string representation of the number contained within this
+ * formattable, or NULL if this object does not contain numeric type.
+ * For values obtained by parsing, the returned decimal number retains
+ * the full precision and range of the original input, unconstrained by
+ * the limits of a double floating point or a 64 bit int.
+ *
+ * This function is not thread safe, and therfore is not declared const,
+ * even though it is logically const.
+ *
+ * Possible errors include U_MEMORY_ALLOCATION_ERROR, and
+ * U_INVALID_STATE if the formattable object has not been set to
+ * a numeric type.
+ *
+ * @param status the error code.
+ * @return the unformatted string representation of a number.
+ * @stable ICU 4.4
+ */
+ StringPiece getDecimalNumber(UErrorCode &status);
+
+ /**
+ * 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);
+
+ /**
+ * Sets the the numeric value from a decimal number string, and changes
+ * the type to to a numeric type appropriate for the number.
+ * The syntax of the number is a "numeric string"
+ * as defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ * The full precision and range of the input number will be retained,
+ * even when it exceeds what can be represented by a double or an int64.
+ *
+ * @param numberString a string representation of the unformatted decimal number.
+ * @param status the error code. Set to U_INVALID_FORMAT_ERROR if the
+ * incoming string is not a valid decimal number.
+ * @stable ICU 4.4
+ */
+ void setDecimalNumber(const StringPiece &numberString,
+ 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();
+
+ /**
+ * 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;
+
+ /**
+ * Internal function, do not use.
+ * TODO: figure out how to make this be non-public.
+ * NumberFormat::format(Formattable, ...
+ * needs to get at the DigitList, if it exists, for
+ * big decimal formatting.
+ * @internal
+ */
+ DigitList *getDigitList() const { return fDecimalNum;}
+
+ /**
+ * Adopt, and set value from, a DigitList
+ * Internal Function, do not use.
+ * @param dl the Digit List to be adopted
+ * @internal
+ */
+ void adoptDigitList(DigitList *dl);
+
+private:
+ /**
+ * Cleans up the memory for unwanted values. For example, the adopted
+ * string or array objects.
+ */
+ void dispose(void);
+
+ /**
+ * Common initialization, for use by constructors.
+ */
+ void init();
+
+ UnicodeString* getBogus() const;
+
+ union {
+ UObject* fObject;
+ UnicodeString* fString;
+ double fDouble;
+ int64_t fInt64;
+ UDate fDate;
+ struct {
+ Formattable* fArray;
+ int32_t fCount;
+ } fArrayAndCount;
+ } fValue;
+
+ CharString *fDecimalStr;
+ DigitList *fDecimalNum;
+
+ 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-4.8.1/i18n/unicode/format.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/format.h
new file mode 100644
index 00000000000..5651c9e44e5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/format.h
@@ -0,0 +1,303 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, 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/fpositer.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;
+ /**
+ * Format an object to produce a string. Subclasses should override this
+ * method. 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+
+ /**
+ * 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;
+
+ /** 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-4.8.1/i18n/unicode/fpositer.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/fpositer.h
new file mode 100644
index 00000000000..ecaa77728ac
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/fpositer.h
@@ -0,0 +1,120 @@
+/*
+********************************************************************************
+* Copyright (C) 2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File attiter.h
+*
+* Modification History:
+*
+* Date Name Description
+* 12/15/2009 dougfelt Created
+********************************************************************************
+*/
+
+#ifndef FPOSITER_H
+#define FPOSITER_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+/**
+ * \file
+ * \brief C++ API: FieldPosition Iterator.
+ */
+
+#if UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Allow the declaration of APIs with pointers to FieldPositionIterator
+ * even when formatting is removed from the build.
+ */
+class FieldPositionIterator;
+
+U_NAMESPACE_END
+
+#else
+
+#include "unicode/fieldpos.h"
+#include "unicode/umisc.h"
+
+U_NAMESPACE_BEGIN
+
+class UVector32;
+
+/**
+ * FieldPositionIterator returns the field ids and their start/limit positions generated
+ * by a call to Format::format. See Format, NumberFormat, DecimalFormat.
+ * @stable ICU 4.4
+ */
+class U_I18N_API FieldPositionIterator : public UObject {
+public:
+ /**
+ * Destructor.
+ * @stable ICU 4.4
+ */
+ ~FieldPositionIterator();
+
+ /**
+ * Constructs a new, empty iterator.
+ * @stable ICU 4.4
+ */
+ FieldPositionIterator(void);
+
+ /**
+ * Copy constructor. If the copy failed for some reason, the new iterator will
+ * be empty.
+ * @stable ICU 4.4
+ */
+ FieldPositionIterator(const FieldPositionIterator&);
+
+ /**
+ * Return true if another object is semantically equal to this
+ * one.
+ * <p>
+ * Return true if this FieldPositionIterator is at the same position in an
+ * equal array of run values.
+ * @stable ICU 4.4
+ */
+ UBool operator==(const FieldPositionIterator&) const;
+
+ /**
+ * Returns the complement of the result of operator==
+ * @param rhs The FieldPositionIterator to be compared for inequality
+ * @return the complement of the result of operator==
+ * @stable ICU 4.4
+ */
+ UBool operator!=(const FieldPositionIterator& rhs) const { return !operator==(rhs); }
+
+ /**
+ * If the current position is valid, updates the FieldPosition values, advances the iterator,
+ * and returns TRUE, otherwise returns FALSE.
+ * @stable ICU 4.4
+ */
+ UBool next(FieldPosition& fp);
+
+private:
+ friend class FieldPositionIteratorHandler;
+
+ /**
+ * Sets the data used by the iterator, and resets the position.
+ * Returns U_ILLEGAL_ARGUMENT_ERROR in status if the data is not valid
+ * (length is not a multiple of 3, or start >= limit for any run).
+ */
+ void setData(UVector32 *adopt, UErrorCode& status);
+
+ UVector32 *data;
+ int32_t pos;
+
+ // No ICU "poor man's RTTI" for this class nor its subclasses.
+ virtual UClassID getDynamicClassID() const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // FPOSITER_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/gregocal.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/gregocal.h
new file mode 100644
index 00000000000..d6be09c0fa6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/gregocal.h
@@ -0,0 +1,815 @@
+/*
+* Copyright (C) 1997-2011, 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(UCAL_MARCH, 1, UCAL_SUNDAY, 2 * 60 * 60 * 1000);
+ * pdt->setEndRule(UCAL_NOVEMBER, 2, UCAL_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( UCAL_ERA, success ) << endl;
+ * cout << "YEAR: " << calendar->get( UCAL_YEAR, success ) << endl;
+ * cout << "MONTH: " << calendar->get( UCAL_MONTH, success ) << endl;
+ * cout << "WEEK_OF_YEAR: " << calendar->get( UCAL_WEEK_OF_YEAR, success ) << endl;
+ * cout << "WEEK_OF_MONTH: " << calendar->get( UCAL_WEEK_OF_MONTH, success ) << endl;
+ * cout << "DATE: " << calendar->get( UCAL_DATE, success ) << endl;
+ * cout << "DAY_OF_MONTH: " << calendar->get( UCAL_DAY_OF_MONTH, success ) << endl;
+ * cout << "DAY_OF_YEAR: " << calendar->get( UCAL_DAY_OF_YEAR, success ) << endl;
+ * cout << "DAY_OF_WEEK: " << calendar->get( UCAL_DAY_OF_WEEK, success ) << endl;
+ * cout << "DAY_OF_WEEK_IN_MONTH: " << calendar->get( UCAL_DAY_OF_WEEK_IN_MONTH, success ) << endl;
+ * cout << "AM_PM: " << calendar->get( UCAL_AM_PM, success ) << endl;
+ * cout << "HOUR: " << calendar->get( UCAL_HOUR, success ) << endl;
+ * cout << "HOUR_OF_DAY: " << calendar->get( UCAL_HOUR_OF_DAY, success ) << endl;
+ * cout << "MINUTE: " << calendar->get( UCAL_MINUTE, success ) << endl;
+ * cout << "SECOND: " << calendar->get( UCAL_SECOND, success ) << endl;
+ * cout << "MILLISECOND: " << calendar->get( UCAL_MILLISECOND, success ) << endl;
+ * cout << "ZONE_OFFSET: " << (calendar->get( UCAL_ZONE_OFFSET, success )/(60*60*1000)) << endl;
+ * cout << "DST_OFFSET: " << (calendar->get( UCAL_DST_OFFSET, success )/(60*60*1000)) << endl;
+ *
+ * cout << "Current Time, with hour reset to 3" << endl;
+ * calendar->clear(UCAL_HOUR_OF_DAY); // so doesn't override
+ * calendar->set(UCAL_HOUR, 3);
+ * cout << "ERA: " << calendar->get( UCAL_ERA, success ) << endl;
+ * cout << "YEAR: " << calendar->get( UCAL_YEAR, success ) << endl;
+ * cout << "MONTH: " << calendar->get( UCAL_MONTH, success ) << endl;
+ * cout << "WEEK_OF_YEAR: " << calendar->get( UCAL_WEEK_OF_YEAR, success ) << endl;
+ * cout << "WEEK_OF_MONTH: " << calendar->get( UCAL_WEEK_OF_MONTH, success ) << endl;
+ * cout << "DATE: " << calendar->get( UCAL_DATE, success ) << endl;
+ * cout << "DAY_OF_MONTH: " << calendar->get( UCAL_DAY_OF_MONTH, success ) << endl;
+ * cout << "DAY_OF_YEAR: " << calendar->get( UCAL_DAY_OF_YEAR, success ) << endl;
+ * cout << "DAY_OF_WEEK: " << calendar->get( UCAL_DAY_OF_WEEK, success ) << endl;
+ * cout << "DAY_OF_WEEK_IN_MONTH: " << calendar->get( UCAL_DAY_OF_WEEK_IN_MONTH, success ) << endl;
+ * cout << "AM_PM: " << calendar->get( UCAL_AM_PM, success ) << endl;
+ * cout << "HOUR: " << calendar->get( UCAL_HOUR, success ) << endl;
+ * cout << "HOUR_OF_DAY: " << calendar->get( UCAL_HOUR_OF_DAY, success ) << endl;
+ * cout << "MINUTE: " << calendar->get( UCAL_MINUTE, success ) << endl;
+ * cout << "SECOND: " << calendar->get( UCAL_SECOND, success ) << endl;
+ * cout << "MILLISECOND: " << calendar->get( UCAL_MILLISECOND, success ) << endl;
+ * cout << "ZONE_OFFSET: " << (calendar->get( UCAL_ZONE_OFFSET, success )/(60*60*1000)) << endl; // in hours
+ * cout << "DST_OFFSET: " << (calendar->get( UCAL_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;
+
+ 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-4.8.1/i18n/unicode/locdspnm.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/locdspnm.h
new file mode 100644
index 00000000000..0faa70379c2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/locdspnm.h
@@ -0,0 +1,188 @@
+/*
+******************************************************************************
+* Copyright (C) 2010-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+******************************************************************************
+*/
+
+#ifndef LOCDSPNM_H
+#define LOCDSPNM_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Provides display names of Locale and its components.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/locid.h"
+#include "unicode/uscript.h"
+#include "unicode/uldnames.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Returns display names of Locales and components of Locales. For
+ * more information on language, script, region, variant, key, and
+ * values, see Locale.
+ * @stable ICU 4.4
+ */
+class U_I18N_API LocaleDisplayNames : public UObject {
+public:
+ /**
+ * Destructor.
+ * @stable ICU 4.4
+ */
+ virtual ~LocaleDisplayNames();
+
+ /**
+ * Convenience overload of
+ * {@link #createInstance(const Locale& locale, UDialectHandling dialectHandling)}
+ * that specifies STANDARD dialect handling.
+ * @param locale the display locale
+ * @return a LocaleDisplayNames instance
+ * @stable ICU 4.4
+ */
+ static LocaleDisplayNames* U_EXPORT2 createInstance(const Locale& locale);
+
+ /**
+ * Returns an instance of LocaleDisplayNames that returns names
+ * formatted for the provided locale, using the provided
+ * dialectHandling.
+ *
+ * @param locale the display locale
+ * @param dialectHandling how to select names for locales
+ * @return a LocaleDisplayNames instance
+ * @stable ICU 4.4
+ */
+ static LocaleDisplayNames* U_EXPORT2 createInstance(const Locale& locale,
+ UDialectHandling dialectHandling);
+
+ // getters for state
+ /**
+ * Returns the locale used to determine the display names. This is
+ * not necessarily the same locale passed to {@link #createInstance}.
+ * @return the display locale
+ * @stable ICU 4.4
+ */
+ virtual const Locale& getLocale() const = 0;
+
+ /**
+ * Returns the dialect handling used in the display names.
+ * @return the dialect handling enum
+ * @stable ICU 4.4
+ */
+ virtual UDialectHandling getDialectHandling() const = 0;
+
+ // names for entire locales
+ /**
+ * Returns the display name of the provided locale.
+ * @param locale the locale whose display name to return
+ * @param result receives the locale's display name
+ * @return the display name of the provided locale
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& localeDisplayName(const Locale& locale,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided locale id.
+ * @param localeId the id of the locale whose display name to return
+ * @param result receives the locale's display name
+ * @return the display name of the provided locale
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& localeDisplayName(const char* localeId,
+ UnicodeString& result) const = 0;
+
+ // names for components of a locale id
+ /**
+ * Returns the display name of the provided language code.
+ * @param lang the language code
+ * @param result receives the language code's display name
+ * @return the display name of the provided language code
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& languageDisplayName(const char* lang,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided script code.
+ * @param script the script code
+ * @param result receives the script code's display name
+ * @return the display name of the provided script code
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& scriptDisplayName(const char* script,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided script code.
+ * @param scriptCode the script code number
+ * @param result receives the script code's display name
+ * @return the display name of the provided script code
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided region code.
+ * @param region the region code
+ * @param result receives the region code's display name
+ * @return the display name of the provided region code
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& regionDisplayName(const char* region,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided variant.
+ * @param variant the variant string
+ * @param result receives the variant's display name
+ * @return the display name of the provided variant
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& variantDisplayName(const char* variant,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided locale key.
+ * @param key the locale key name
+ * @param result receives the locale key's display name
+ * @return the display name of the provided locale key
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& keyDisplayName(const char* key,
+ UnicodeString& result) const = 0;
+
+ /**
+ * Returns the display name of the provided value (used with the provided key).
+ * @param key the locale key name
+ * @param value the locale key's value
+ * @param result receives the value's display name
+ * @return the display name of the provided value
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& keyValueDisplayName(const char* key, const char* value,
+ UnicodeString& result) const = 0;
+
+private:
+ // No ICU "poor man's RTTI" for this class nor its subclasses.
+ virtual UClassID getDynamicClassID() const;
+};
+
+inline LocaleDisplayNames::~LocaleDisplayNames() {
+}
+
+inline LocaleDisplayNames* LocaleDisplayNames::createInstance(const Locale& locale) {
+ return LocaleDisplayNames::createInstance(locale, ULDN_STANDARD_NAMES);
+}
+
+U_NAMESPACE_END
+
+#endif
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/measfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/measfmt.h
new file mode 100644
index 00000000000..a5af55e9d53
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/measunit.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/measunit.h
new file mode 100644
index 00000000000..9a210e65957
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/measure.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/measure.h
new file mode 100644
index 00000000000..6b7a0497b47
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/msgfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/msgfmt.h
new file mode 100644
index 00000000000..b2fc2b2b6a4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/msgfmt.h
@@ -0,0 +1,1089 @@
+/*
+* Copyright (C) 2007-2011, 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/messagepattern.h"
+#include "unicode/parseerr.h"
+#include "unicode/plurfmt.h"
+#include "unicode/plurrule.h"
+
+U_CDECL_BEGIN
+// Forward declaration.
+struct UHashtable;
+typedef struct UHashtable UHashtable;
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+class AppendableWrapper;
+class DateFormat;
+class NumberFormat;
+
+/**
+ * <p>MessageFormat prepares strings for display to users,
+ * with optional arguments (variables/placeholders).
+ * The arguments can occur in any order, which is necessary for translation
+ * into languages with different grammars.
+ *
+ * <p>A MessageFormat is constructed from a <em>pattern</em> string
+ * with arguments in {curly braces} which will be replaced by formatted values.
+ *
+ * <p><code>MessageFormat</code> differs from the other <code>Format</code>
+ * classes in that you create a <code>MessageFormat</code> object with one
+ * of its constructors (not with a <code>createInstance</code> style factory
+ * method). Factory methods aren't necessary because <code>MessageFormat</code>
+ * itself doesn't implement locale-specific behavior. Any locale-specific
+ * behavior is defined by the pattern that you provide and the
+ * subformats used for inserted arguments.
+ *
+ * <p>Arguments can be named (using identifiers) or numbered (using small ASCII-digit integers).
+ * Some of the API methods work only with argument numbers and throw an exception
+ * if the pattern has named arguments (see {@link #usesNamedArguments()}).
+ *
+ * <p>An argument might not specify any format type. In this case,
+ * a Number value is formatted with a default (for the locale) NumberFormat,
+ * a Date value is formatted with a default (for the locale) DateFormat,
+ * and for any other value its toString() value is used.
+ *
+ * <p>An argument might specify a "simple" type for which the specified
+ * Format object is created, cached and used.
+ *
+ * <p>An argument might have a "complex" type with nested MessageFormat sub-patterns.
+ * During formatting, one of these sub-messages is selected according to the argument value
+ * and recursively formatted.
+ *
+ * <p>After construction, a custom Format object can be set for
+ * a top-level argument, overriding the default formatting and parsing behavior
+ * for that argument.
+ * However, custom formatting can be achieved more simply by writing
+ * a typeless argument in the pattern string
+ * and supplying it with a preformatted string value.
+ *
+ * <p>When formatting, MessageFormat takes a collection of argument values
+ * and writes an output string.
+ * The argument values may be passed as an array
+ * (when the pattern contains only numbered arguments)
+ * or as an array of names and and an array of arguments (which works for both named
+ * and numbered arguments).
+ *
+ * <p>Each argument is matched with one of the input values by array index or argument name
+ * and formatted according to its pattern specification
+ * (or using a custom Format object if one was set).
+ * A numbered pattern argument is matched with an argument name that contains that number
+ * as an ASCII-decimal-digit string (without leading zero).
+ *
+ * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
+ *
+ * <code>MessageFormat</code> uses patterns of the following form:
+ * <pre>
+ * message = messageText (argument messageText)*
+ * argument = noneArg | simpleArg | complexArg
+ * complexArg = choiceArg | pluralArg | selectArg
+ *
+ * noneArg = '{' argNameOrNumber '}'
+ * simpleArg = '{' argNameOrNumber ',' argType [',' argStyle] '}'
+ * choiceArg = '{' argNameOrNumber ',' "choice" ',' choiceStyle '}'
+ * pluralArg = '{' argNameOrNumber ',' "plural" ',' pluralStyle '}'
+ * selectArg = '{' argNameOrNumber ',' "select" ',' selectStyle '}'
+ *
+ * choiceStyle: see {@link ChoiceFormat}
+ * pluralStyle: see {@link PluralFormat}
+ * selectStyle: see {@link SelectFormat}
+ *
+ * argNameOrNumber = argName | argNumber
+ * argName = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
+ * argNumber = '0' | ('1'..'9' ('0'..'9')*)
+ *
+ * argType = "number" | "date" | "time" | "spellout" | "ordinal" | "duration"
+ * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText
+ * </pre>
+ *
+ * <ul>
+ * <li>messageText can contain quoted literal strings including syntax characters.
+ * A quoted literal string begins with an ASCII apostrophe and a syntax character
+ * (usually a {curly brace}) and continues until the next single apostrophe.
+ * A double ASCII apostrohpe inside or outside of a quoted string represents
+ * one literal apostrophe.
+ * <li>Quotable syntax characters are the {curly braces} in all messageText parts,
+ * plus the '#' sign in a messageText immediately inside a pluralStyle,
+ * and the '|' symbol in a messageText immediately inside a choiceStyle.
+ * <li>See also {@link #UMessagePatternApostropheMode}
+ * <li>In argStyleText, every single ASCII apostrophe begins and ends quoted literal text,
+ * and unquoted {curly braces} must occur in matched pairs.
+ * </ul>
+ *
+ * <p>Recommendation: Use the real apostrophe (single quote) character
+ * \htmlonly&#x2019;\endhtmlonly (U+2019) for
+ * human-readable text, and 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>The <code>argType</code> and <code>argStyle</code> values are used to create
+ * a <code>Format</code> instance for the format element. The following
+ * table shows how the values map to Format instances. Combinations not
+ * shown in the table are illegal. Any <code>argStyleText</code> must
+ * be a valid pattern string for the Format subclass used.
+ *
+ * <p><table border=1>
+ * <tr>
+ * <th>argType
+ * <th>argStyle
+ * <th>resulting Format object
+ * <tr>
+ * <td colspan=2><i>(none)</i>
+ * <td><code>null</code>
+ * <tr>
+ * <td rowspan=5><code>number</code>
+ * <td><i>(none)</i>
+ * <td><code>NumberFormat.createInstance(getLocale(), status)</code>
+ * <tr>
+ * <td><code>integer</code>
+ * <td><code>NumberFormat.createInstance(getLocale(), kNumberStyle, status)</code>
+ * <tr>
+ * <td><code>currency</code>
+ * <td><code>NumberFormat.createCurrencyInstance(getLocale(), status)</code>
+ * <tr>
+ * <td><code>percent</code>
+ * <td><code>NumberFormat.createPercentInstance(getLocale(), status)</code>
+ * <tr>
+ * <td><i>argStyleText</i>
+ * <td><code>new DecimalFormat(argStyleText, new DecimalFormatSymbols(getLocale(), status), status)</code>
+ * <tr>
+ * <td rowspan=6><code>date</code>
+ * <td><i>(none)</i>
+ * <td><code>DateFormat.createDateInstance(kDefault, getLocale(), status)</code>
+ * <tr>
+ * <td><code>short</code>
+ * <td><code>DateFormat.createDateInstance(kShort, getLocale(), status)</code>
+ * <tr>
+ * <td><code>medium</code>
+ * <td><code>DateFormat.createDateInstance(kDefault, getLocale(), status)</code>
+ * <tr>
+ * <td><code>long</code>
+ * <td><code>DateFormat.createDateInstance(kLong, getLocale(), status)</code>
+ * <tr>
+ * <td><code>full</code>
+ * <td><code>DateFormat.createDateInstance(kFull, getLocale(), status)</code>
+ * <tr>
+ * <td><i>argStyleText</i>
+ * <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)
+ * <tr>
+ * <td rowspan=6><code>time</code>
+ * <td><i>(none)</i>
+ * <td><code>DateFormat.createTimeInstance(kDefault, getLocale(), status)</code>
+ * <tr>
+ * <td><code>short</code>
+ * <td><code>DateFormat.createTimeInstance(kShort, getLocale(), status)</code>
+ * <tr>
+ * <td><code>medium</code>
+ * <td><code>DateFormat.createTimeInstance(kDefault, getLocale(), status)</code>
+ * <tr>
+ * <td><code>long</code>
+ * <td><code>DateFormat.createTimeInstance(kLong, getLocale(), status)</code>
+ * <tr>
+ * <td><code>full</code>
+ * <td><code>DateFormat.createTimeInstance(kFull, getLocale(), status)</code>
+ * <tr>
+ * <td><i>argStyleText</i>
+ * <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)
+ * <tr>
+ * <td><code>spellout</code>
+ * <td><i>argStyleText (optional)</i>
+ * <td><code>new RuleBasedNumberFormat(URBNF_SPELLOUT, getLocale(), status)
+ * <br/>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText, status);</code>
+ * <tr>
+ * <td><code>ordinal</code>
+ * <td><i>argStyleText (optional)</i>
+ * <td><code>new RuleBasedNumberFormat(URBNF_ORDINAL, getLocale(), status)
+ * <br/>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText, status);</code>
+ * <tr>
+ * <td><code>duration</code>
+ * <td><i>argStyleText (optional)</i>
+ * <td><code>new RuleBasedNumberFormat(URBNF_DURATION, getLocale(), status)
+ * <br/>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText, status);</code>
+ * </table>
+ * <p>
+ *
+ * <h4>Usage Information</h4>
+ *
+ * <p>Here are some examples of usage:
+ * 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>
+ *
+ *
+ * <p>For messages that include plural forms, you can use a plural argument:
+ * <pre>
+ * \code
+ * success = U_ZERO_ERROR;
+ * MessageFormat msgFmt(
+ * "{num_files, plural, "
+ * "=0{There are no files on disk \"{disk_name}\".}"
+ * "=1{There is one file on disk \"{disk_name}\".}"
+ * "other{There are # files on disk \"{disk_name}\".}}",
+ * Locale("en"),
+ * success);
+ * FieldPosition fpos = 0;
+ * Formattable testArgs[] = {0L, "MyDisk"};
+ * UnicodeString testArgsNames[] = {"num_files", "disk_name"};
+ * UnicodeString result;
+ * cout << msgFmt.format(testArgs, testArgsNames, 2, result, fpos, 0, success);
+ * testArgs[0] = 3L;
+ * cout << msgFmt.format(testArgs, testArgsNames, 2, result, fpos, 0, success);
+ * \endcode
+ * <em>output</em>:
+ * There are no files on disk "MyDisk".
+ * There are 3 files on "MyDisk".
+ * </pre>
+ * See {@link PluralFormat} and {@link PluralRules} for details.
+ *
+ * <h4><a name="synchronization">Synchronization</a></h4>
+ *
+ * <p>MessageFormats are not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * @stable ICU 2.0
+ */
+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 receive information on the position
+ * of an 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 to be used for creating argument Format objects.
+ * @param theLocale the new locale value to be set.
+ * @stable ICU 2.0
+ */
+ virtual void setLocale(const Locale& theLocale);
+
+ /**
+ * Gets the locale used for creating argument Format objects.
+ * 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 receive information on the position
+ * of an error within the 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);
+
+ /**
+ * Sets the UMessagePatternApostropheMode and the pattern used by this message format.
+ * Parses the pattern and caches Format objects for simple argument types.
+ * Patterns and their interpretation are specified in the
+ * <a href="#patterns">class description</a>.
+ * <p>
+ * This method is best used only once on a given object to avoid confusion about the mode,
+ * and after constructing the object with an empty pattern string to minimize overhead.
+ *
+ * @param pattern The pattern to be applied.
+ * @param aposMode The new apostrophe mode.
+ * @param parseError Struct to receive information on the position
+ * of an error within the pattern.
+ * Can be NULL.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @draft ICU 4.8
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UMessagePatternApostropheMode aposMode,
+ UParseError* parseError,
+ UErrorCode& status);
+
+ /**
+ * @return this instance's UMessagePatternApostropheMode.
+ * @draft ICU 4.8
+ */
+ UMessagePatternApostropheMode getApostropheMode() const {
+ return msgPattern.getApostropheMode();
+ }
+
+ /**
+ * 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.
+ *
+ * <p>If this format uses named arguments, the new formats are discarded
+ * and this format remains 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.
+ *
+ * <p>If this format uses named arguments, the new formats are discarded
+ * and this format remains 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.
+ *
+ * <p>If this format uses named arguments, the new format is discarded
+ * and this format remains unchanged.
+ *
+ * @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 format names. This function returns formatNames in StringEnumerations
+ * which can be used with getFormat() and setFormat() to export formattable
+ * array from current MessageFormat to another. It is the caller's responsibility
+ * to delete the returned formatNames.
+ * @param status output param set to success/failure code.
+ * @stable ICU 4.0
+ */
+ virtual StringEnumeration* getFormatNames(UErrorCode& status);
+
+ /**
+ * Gets subformat pointer for given format name.
+ * This function supports both named and numbered
+ * arguments. If numbered, the formatName is the
+ * corresponding UnicodeStrings (e.g. "0", "1", "2"...).
+ * The returned Format object should not be deleted by the caller,
+ * nor should the ponter of other object . The pointer and its
+ * contents remain valid only until the next call to any method
+ * of this class is made with this object.
+ * @param formatName the name or number specifying a format
+ * @param status output param set to success/failure code.
+ * @stable ICU 4.0
+ */
+ virtual Format* getFormat(const UnicodeString& formatName, UErrorCode& status);
+
+ /**
+ * Sets one subformat for given format name.
+ * See the class description about format name.
+ * This function supports both named and numbered
+ * arguments-- if numbered, the formatName is the
+ * corresponding UnicodeStrings (e.g. "0", "1", "2"...).
+ * If there is no matched formatName or wrong type,
+ * the item will be ignored.
+ * @param formatName Name of the subformat.
+ * @param format the format to be set.
+ * @param status output param set to success/failure code.
+ * @stable ICU 4.0
+ */
+ virtual void setFormat(const UnicodeString& formatName, const Format& format, UErrorCode& status);
+
+ /**
+ * Sets one subformat for given format name.
+ * See the class description about format name.
+ * This function supports both named and numbered
+ * arguments-- if numbered, the formatName is the
+ * corresponding UnicodeStrings (e.g. "0", "1", "2"...).
+ * If there is no matched formatName or wrong type,
+ * the item will be ignored.
+ * The caller should not delete the Format object after this call.
+ * @param formatName Name of the subformat.
+ * @param formatToAdopt Format to be adopted.
+ * @param status output param set to success/failure code.
+ * @stable ICU 4.0
+ */
+ virtual void adoptFormat(const UnicodeString& formatName, Format* formatToAdopt, UErrorCode& status);
+
+ /**
+ * 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 this format. 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;
+
+
+ using Format::format;
+
+ /**
+ * Formats the given array of arguments into a user-readable string.
+ * Does not take ownership of the Formattable* array or its contents.
+ *
+ * <p>If this format uses named arguments, appendTo is unchanged and
+ * status is set to U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @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.
+ *
+ * <p>If this format uses named arguments, appendTo is unchanged and
+ * status is set to U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @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.
+ *
+ * <p>If this format uses named arguments, appendTo is unchanged and
+ * status is set to U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @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;
+
+
+ /**
+ * Formats the given array of arguments into a user-defined argument name
+ * array. This function supports both named and numbered
+ * arguments-- if numbered, the formatName is the
+ * corresponding UnicodeStrings (e.g. "0", "1", "2"...).
+ *
+ * @param argumentNames argument name array
+ * @param arguments An array of objects to be formatted.
+ * @param count The number of elements of 'argumentNames' and
+ * arguments. The number of argumentNames and arguments
+ * must be the same.
+ * @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 4.0
+ */
+ UnicodeString& format(const UnicodeString* argumentNames,
+ const Formattable* arguments,
+ int32_t count,
+ 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.
+ *
+ * <p>If this format uses named arguments, status is set to
+ * U_ARGUMENT_TYPE_MISMATCH.
+ *
+ * @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. Returns NULL if status is not U_ZERO_ERROR.
+ *
+ * @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 true if this MessageFormat uses named arguments,
+ * and false otherwise. See class description.
+ *
+ * @return true if named arguments are used.
+ * @stable ICU 4.0
+ */
+ UBool usesNamedArguments() const;
+
+
+ /**
+ * This API is for ICU internal use only.
+ * Please do not use it.
+ *
+ * Returns argument types count in the parsed pattern.
+ * Used to distinguish pattern "{0} d" and "d".
+ *
+ * @return The number of formattable types in the pattern
+ * @internal
+ */
+ int32_t getArgTypeCount() 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;
+
+ /**
+ * 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);
+
+ /**
+ * Compares two Format objects. This is used for constructing the hash
+ * tables.
+ *
+ * @param left pointer to a Format object. Must not be NULL.
+ * @param right pointer to a Format object. Must not be NULL.
+ *
+ * @return whether the two objects are the same
+ * @internal
+ */
+ static UBool equalFormats(const void* left, const void* right);
+
+private:
+
+ Locale fLocale;
+ MessagePattern msgPattern;
+ Format** formatAliases; // see getFormats
+ int32_t formatAliasesCapacity;
+
+ MessageFormat(); // default constructor not implemented
+
+ /**
+ * This provider helps defer instantiation of a PluralRules object
+ * until we actually need to select a keyword.
+ * For example, if the number matches an explicit-value selector like "=1"
+ * we do not need any PluralRules.
+ */
+ class U_I18N_API PluralSelectorProvider : public PluralFormat::PluralSelector {
+ public:
+ PluralSelectorProvider(const Locale* loc);
+ virtual ~PluralSelectorProvider();
+ virtual UnicodeString select(double number, UErrorCode& ec) const;
+
+ void reset(const Locale* loc);
+ private:
+ const Locale* locale;
+ PluralRules* rules;
+ };
+
+ /**
+ * 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;
+
+ /**
+ * TRUE if there are different argTypes for the same argument.
+ * This only matters when the MessageFormat is used in the plain C (umsg_xxx) API
+ * where the pattern argTypes determine how the va_arg list is read.
+ */
+ UBool hasArgTypeConflicts;
+
+ // Variable-size array management
+ UBool allocateArgTypes(int32_t capacity, UErrorCode& status);
+
+ /**
+ * 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;
+
+ UHashtable* cachedFormatters;
+ UHashtable* customFormatArgStarts;
+
+ PluralSelectorProvider pluralProvider;
+
+ /**
+ * 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);
+
+ /**
+ * Thin wrapper around the format(... AppendableWrapper ...) variant.
+ * Wraps the destination UnicodeString into an AppendableWrapper and
+ * supplies default values for some other parameters.
+ */
+ UnicodeString& format(const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition* pos,
+ UErrorCode& status) const;
+
+ /**
+ * Formats the arguments and writes the result into the
+ * AppendableWrapper, updates the field position.
+ *
+ * @param msgStart Index to msgPattern part to start formatting from.
+ * @param pluralNumber Zero except when formatting a plural argument sub-message
+ * where a '#' is replaced by the format string for this number.
+ * @param arguments The formattable objects array. (Must not be NULL.)
+ * @param argumentNames NULL if numbered values are used. Otherwise the same
+ * length as "arguments", and each entry is the name of the
+ * corresponding argument in "arguments".
+ * @param cnt The length of arguments (and of argumentNames if that is not NULL).
+ * @param appendTo Output parameter to receive the result.
+ * The result string is appended to existing contents.
+ * @param pos Field position status.
+ * @param success The error code status.
+ */
+ void format(int32_t msgStart,
+ double pluralNumber,
+ const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ AppendableWrapper& appendTo,
+ FieldPosition* pos,
+ UErrorCode& success) const;
+
+ UnicodeString getArgName(int32_t partIndex);
+
+ void setArgStartFormat(int32_t argStart, Format* formatter, UErrorCode& status);
+
+ void setCustomArgStartFormat(int32_t argStart, Format* formatter, UErrorCode& status);
+
+ int32_t nextTopLevelArgStart(int32_t partIndex) const;
+
+ UBool argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber);
+
+ void cacheExplicitFormats(UErrorCode& status);
+
+ Format* createAppropriateFormat(UnicodeString& type,
+ UnicodeString& style,
+ Formattable::Type& formattableType,
+ UParseError& parseError,
+ UErrorCode& ec);
+
+ const Formattable* getArgFromListByName(const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt, UnicodeString& name) const;
+
+ Formattable* parse(int32_t msgStart,
+ const UnicodeString& source,
+ ParsePosition& pos,
+ int32_t& count,
+ UErrorCode& ec) const;
+
+ FieldPosition* updateMetaData(AppendableWrapper& dest, int32_t prevLength,
+ FieldPosition* fp, const Formattable* argId) const;
+
+ Format* getCachedFormatter(int32_t argumentNumber) const;
+
+ UnicodeString getLiteralStringUntilNextArgument(int32_t from) const;
+
+ void copyObjects(const MessageFormat& that, UErrorCode& ec);
+
+ void formatComplexSubMessage(int32_t msgStart,
+ double pluralNumber,
+ const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ AppendableWrapper& appendTo,
+ UErrorCode& success) const;
+
+ /**
+ * Convenience method that ought to be in NumberFormat
+ */
+ NumberFormat* createIntegerFormat(const Locale& locale, UErrorCode& status) const;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Resets the internal MessagePattern, and other associated caches.
+ */
+ void resetPattern();
+
+ /**
+ * A DummyFormatter that we use solely to store a NULL value. UHash does
+ * not support storing NULL values.
+ * @internal
+ */
+ class U_I18N_API DummyFormat : public Format {
+ public:
+ virtual UBool operator==(const Format&) const;
+ virtual Format* clone() const;
+ virtual UnicodeString& format(const Formattable&,
+ UnicodeString& appendTo,
+ FieldPosition&,
+ UErrorCode& status) const;
+ virtual void parseObject(const UnicodeString&,
+ Formattable&,
+ ParsePosition&) const;
+ virtual UClassID getDynamicClassID() const;
+ };
+
+ 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-4.8.1/i18n/unicode/numfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/numfmt.h
new file mode 100644
index 00000000000..43964952a28
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/numfmt.h
@@ -0,0 +1,1062 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2011, 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"
+#include "unicode/stringpiece.h"
+
+class NumberFormatTest;
+
+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>
+ * Starting from ICU 4.2, you can use createInstance() by passing in a 'style'
+ * as parameter to get the correct instance.
+ * For example,
+ * use createInstance(...kNumberStyle...) to get the normal number format,
+ * createInstance(...kPercentStyle...) to get a format for displaying
+ * percentage,
+ * createInstance(...kScientificStyle...) to get a format for displaying
+ * scientific number,
+ * createInstance(...kCurrencyStyle...) to get the currency number format,
+ * in which the currency is represented by its symbol, for example, "$3.00".
+ * createInstance(...kIsoCurrencyStyle...) to get the currency number format,
+ * in which the currency is represented by its ISO code, for example "USD3.00".
+ * createInstance(...kPluralCurrencyStyle...) to get the currency number format,
+ * in which the currency is represented by its full name in plural format,
+ * for example, "3.00 US dollars" or "1.00 US dollar".
+ * <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.
+ *
+ * Note: as of ICU 4.4, the values in this enum have been extended to
+ * support identification of all number format fields, not just those
+ * pertaining to alignment.
+ *
+ * @see FieldPosition
+ * @stable ICU 2.0
+ */
+ enum EAlignmentFields {
+ kIntegerField,
+ kFractionField,
+ kDecimalSeparatorField,
+ kExponentSymbolField,
+ kExponentSignField,
+ kExponentField,
+ kGroupingSeparatorField,
+ kCurrencyField,
+ kPercentField,
+ kPermillField,
+ kSignField,
+
+ /**
+ * 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;
+
+
+ using Format::format;
+
+ /**
+ * 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;
+
+ /**
+ * 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Can be
+ * NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ 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 double number. Subclasses must implement
+ * this method.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) 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.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const = 0;
+
+ /**
+ * Format an int32 number. Subclasses must implement
+ * this method.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+ /**
+ * 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;
+ /**
+ * Format an int64 number. Subclasses must implement
+ * this method.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+
+ /**
+ * Format a decimal number. Subclasses must implement
+ * this method. The syntax of the unformatted number is a "numeric string"
+ * as defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ *
+ * @param number The unformatted number, as a string, to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * Can be NULL.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable 4.4
+ */
+ virtual UnicodeString& format(const StringPiece &number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+public:
+ /**
+ * Format a decimal number.
+ * The number is a DigitList wrapper onto a floating point decimal number.
+ * The default implementation in NumberFormat converts the decimal number
+ * to a double and formats that. Subclasses of NumberFormat that want
+ * to specifically handle big decimal numbers must override this method.
+ * class DecimalFormat does so.
+ *
+ * @param number The number, a DigitList format Decimal Floating Point.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @internal
+ */
+ virtual UnicodeString& format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const;
+
+ /**
+ * Format a decimal number.
+ * The number is a DigitList wrapper onto a floating point decimal number.
+ * The default implementation in NumberFormat converts the decimal number
+ * to a double and formats that. Subclasses of NumberFormat that want
+ * to specifically handle big decimal numbers must override this method.
+ * class DecimalFormat does so.
+ *
+ * @param number The number, a DigitList format Decimal Floating Point.
+ * @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.
+ * @internal
+ */
+ virtual UnicodeString& format(const DigitList &number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+public:
+
+ /**
+ * 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);
+
+ /**
+ * Sets whether lenient parsing should be enabled (it is off by default).
+ *
+ * @param enable <code>TRUE</code> if lenient parsing should be used,
+ * <code>FALSE</code> otherwise.
+ * @draft ICU 4.8
+ */
+ virtual void setLenient(UBool enable);
+
+ /**
+ * Returns whether lenient parsing is enabled (it is off by default).
+ *
+ * @return <code>TRUE</code> if lenient parsing is enabled,
+ * <code>FALSE</code> otherwise.
+ * @see #setLenient
+ * @draft ICU 4.8
+ */
+ virtual UBool isLenient(void) const;
+
+ /**
+ * 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&);
+
+ /**
+ * Creates the specified decimal format style of the desired locale.
+ * @param desiredLocale the given locale.
+ * @param style the given style.
+ * @param errorCode Output param filled with success/failure status.
+ * @return A new NumberFormat instance.
+ * @draft ICU 4.8
+ */
+ static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale,
+ UNumberFormatStyle style,
+ UErrorCode& errorCode);
+
+
+ /**
+ * 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:
+
+ static UBool isStyleSupported(UNumberFormatStyle style);
+
+ /**
+ * Creates the specified decimal format style of the desired locale.
+ * @param desiredLocale the given locale.
+ * @param style the given style.
+ * @param errorCode Output param filled with success/failure status.
+ * @return A new NumberFormat instance.
+ */
+ static NumberFormat* makeInstance(const Locale& desiredLocale,
+ UNumberFormatStyle style,
+ UErrorCode& errorCode);
+
+ UBool fGroupingUsed;
+ int32_t fMaxIntegerDigits;
+ int32_t fMinIntegerDigits;
+ int32_t fMaxFractionDigits;
+ int32_t fMinFractionDigits;
+ UBool fParseIntegerOnly;
+ UBool fLenient; // TRUE => lenient parse is enabled
+
+ // ISO currency code
+ UChar fCurrency[4];
+
+ friend class ICUNumberFormatFactory; // access to makeInstance
+ friend class ICUNumberFormatService;
+ friend class ::NumberFormatTest; // access to isStyleSupported()
+};
+
+#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 UBool
+NumberFormat::isLenient() const
+{
+ return fLenient;
+}
+
+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-4.8.1/i18n/unicode/numsys.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/numsys.h
new file mode 100644
index 00000000000..4fed0029703
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/numsys.h
@@ -0,0 +1,191 @@
+/*
+*******************************************************************************
+* Copyright (C) 2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+*
+* File NUMSYS.H
+*
+* Modification History:*
+* Date Name Description
+*
+********************************************************************************
+*/
+
+#ifndef NUMSYS
+#define NUMSYS
+
+/**
+ * \def NUMSYS_NAME_CAPACITY
+ * Size of a numbering system name.
+ * @internal
+ */
+#define NUMSYS_NAME_CAPACITY 8
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: NumberingSystem object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+
+#include "unicode/format.h"
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Defines numbering systems. A numbering system describes the scheme by which
+ * numbers are to be presented to the end user. In its simplest form, a numbering
+ * system describes the set of digit characters that are to be used to display
+ * numbers, such as Western digits, Thai digits, Arabic-Indic digits, etc.
+ * More complicated numbering systems are algorithmic in nature, and require use
+ * of an RBNF formatter ( rule based number formatter ), in order to calculate
+ * the characters to be displayed for a given number. Examples of algorithmic
+ * numbering systems include Roman numerals, Chinese numerals, and Hebrew numerals.
+ * Formatting rules for many commonly used numbering systems are included in
+ * the ICU package, based on the numbering system rules defined in CLDR.
+ * Alternate numbering systems can be specified to a locale by using the
+ * numbers locale keyword.
+ */
+
+class U_I18N_API NumberingSystem : public UObject {
+public:
+
+ /**
+ * Default Constructor.
+ *
+ * @stable ICU 4.2
+ */
+ NumberingSystem();
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.2
+ */
+ NumberingSystem(const NumberingSystem& other);
+
+ /**
+ * Destructor.
+ * @stable ICU 4.2
+ */
+ virtual ~NumberingSystem();
+
+ /**
+ * Create the default numbering system associated with the specified locale.
+ * @param inLocale The given locale.
+ * @param status ICU status
+ * @stable ICU 4.2
+ */
+ static NumberingSystem* U_EXPORT2 createInstance(const Locale & inLocale, UErrorCode& status);
+
+ /**
+ * Create the default numbering system associated with the default locale.
+ * @stable ICU 4.2
+ */
+ static NumberingSystem* U_EXPORT2 createInstance(UErrorCode& status);
+
+ /**
+ * Create a numbering system using the specified radix, type, and description.
+ * @param radix The radix (base) for this numbering system.
+ * @param isAlgorithmic TRUE if the numbering system is algorithmic rather than numeric.
+ * @param description The string representing the set of digits used in a numeric system, or the name of the RBNF
+ * ruleset to be used in an algorithmic system.
+ * @param status ICU status
+ * @stable ICU 4.2
+ */
+ static NumberingSystem* U_EXPORT2 createInstance(int32_t radix, UBool isAlgorithmic, const UnicodeString& description, UErrorCode& status );
+
+ /**
+ * Return a StringEnumeration over all the names of numbering systems known to ICU.
+ * @stable ICU 4.2
+ */
+
+ static StringEnumeration * U_EXPORT2 getAvailableNames(UErrorCode& status);
+
+ /**
+ * Create a numbering system from one of the predefined numbering systems known to ICU.
+ * @param name The name of the numbering system.
+ * @param status ICU status
+ * @stable ICU 4.2
+ */
+ static NumberingSystem* U_EXPORT2 createInstanceByName(const char* name, UErrorCode& status);
+
+
+ /**
+ * Returns the radix of this numbering system.
+ * @stable ICU 4.2
+ */
+ int32_t getRadix();
+
+ /**
+ * Returns the name of this numbering system if it was created using one of the predefined names
+ * known to ICU. Otherwise, returns NULL.
+ * @draft ICU 4.6
+ */
+ const char * getName();
+
+ /**
+ * Returns the description string of this numbering system, which is either
+ * the string of digits in the case of simple systems, or the ruleset name
+ * in the case of algorithmic systems.
+ * @stable ICU 4.2
+ */
+ virtual UnicodeString getDescription();
+
+
+
+ /**
+ * Returns TRUE if the given numbering system is algorithmic
+ *
+ * @return TRUE if the numbering system is algorithmic.
+ * Otherwise, return FALSE.
+ * @stable ICU 4.2
+ */
+ UBool isAlgorithmic() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 4.2
+ *
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 4.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+
+private:
+ UnicodeString desc;
+ int32_t radix;
+ UBool algorithmic;
+ char name[NUMSYS_NAME_CAPACITY+1];
+
+ void setRadix(int32_t radix);
+
+ void setAlgorithmic(UBool algorithmic);
+
+ void setDesc(UnicodeString desc);
+
+ void setName(const char* name);
+
+ static UBool isValidDigitString(const UnicodeString &str);
+
+ UBool hasContiguousDecimalDigits() const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _NUMSYS
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurfmt.h
new file mode 100644
index 00000000000..cc1a426a57c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurfmt.h
@@ -0,0 +1,552 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+
+* File PLURFMT.H
+*
+* Modification History:*
+* Date Name Description
+*
+********************************************************************************
+*/
+
+#ifndef PLURFMT
+#define PLURFMT
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: PluralFormat object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/messagepattern.h"
+#include "unicode/numfmt.h"
+#include "unicode/plurrule.h"
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+
+/**
+ * <p>
+ * <code>PluralFormat</code> supports the creation of internationalized
+ * messages with plural inflection. It is based on <i>plural
+ * selection</i>, i.e. the caller specifies messages for each
+ * plural case that can appear in the user's language and the
+ * <code>PluralFormat</code> selects the appropriate message based on
+ * the number.
+ * </p>
+ * <h4>The Problem of Plural Forms in Internationalized Messages</h4>
+ * <p>
+ * Different languages have different ways to inflect
+ * plurals. Creating internationalized messages that include plural
+ * forms is only feasible when the framework is able to handle plural
+ * forms of <i>all</i> languages correctly. <code>ChoiceFormat</code>
+ * doesn't handle this well, because it attaches a number interval to
+ * each message and selects the message whose interval contains a
+ * given number. This can only handle a finite number of
+ * intervals. But in some languages, like Polish, one plural case
+ * applies to infinitely many intervals (e.g., the plural case applies to
+ * numbers ending with 2, 3, or 4 except those ending with 12, 13, or
+ * 14). Thus <code>ChoiceFormat</code> is not adequate.
+ * </p><p>
+ * <code>PluralFormat</code> deals with this by breaking the problem
+ * into two parts:
+ * <ul>
+ * <li>It uses <code>PluralRules</code> that can define more complex
+ * conditions for a plural case than just a single interval. These plural
+ * rules define both what plural cases exist in a language, and to
+ * which numbers these cases apply.
+ * <li>It provides predefined plural rules for many languages. Thus, the programmer
+ * need not worry about the plural cases of a language and
+ * does not have to define the plural cases; they can simply
+ * use the predefined keywords. The whole plural formatting of messages can
+ * be done using localized patterns from resource bundles. For predefined plural
+ * rules, see the CLDR <i>Language Plural Rules</i> page at
+ * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
+ * </ul>
+ * </p>
+ * <h4>Usage of <code>PluralFormat</code></h4>
+ * <p>Note: Typically, plural formatting is done via <code>MessageFormat</code>
+ * with a <code>plural</code> argument type,
+ * rather than using a stand-alone <code>PluralFormat</code>.
+ * </p><p>
+ * This discussion assumes that you use <code>PluralFormat</code> with
+ * a predefined set of plural rules. You can create one using one of
+ * the constructors that takes a <code>locale</code> object. To
+ * specify the message pattern, you can either pass it to the
+ * constructor or set it explicitly using the
+ * <code>applyPattern()</code> method. The <code>format()</code>
+ * method takes a number object and selects the message of the
+ * matching plural case. This message will be returned.
+ * </p>
+ * <h5>Patterns and Their Interpretation</h5>
+ * <p>
+ * The pattern text defines the message output for each plural case of the
+ * specified locale. Syntax:
+ * <pre>
+ * pluralStyle = [offsetValue] (selector '{' message '}')+
+ * offsetValue = "offset:" number
+ * selector = explicitValue | keyword
+ * explicitValue = '=' number // adjacent, no white space in between
+ * keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
+ * message: see {@link MessageFormat}
+ * </pre>
+ * Pattern_White_Space between syntax elements is ignored, except
+ * between the {curly braces} and their sub-message,
+ * and between the '=' and the number of an explicitValue.
+ *
+ * </p><p>
+ * There are 6 predefined casekeyword in CLDR/ICU - 'zero', 'one', 'two', 'few', 'many' and
+ * 'other'. You always have to define a message text for the default plural case
+ * <code>other</code> which is contained in every rule set.
+ * If you do not specify a message text for a particular plural case, the
+ * message text of the plural case <code>other</code> gets assigned to this
+ * plural case.
+ * </p><p>
+ * When formatting, the input number is first matched against the explicitValue clauses.
+ * If there is no exact-number match, then a keyword is selected by calling
+ * the <code>PluralRules</code> with the input number <em>minus the offset</em>.
+ * (The offset defaults to 0 if it is omitted from the pattern string.)
+ * If there is no clause with that keyword, then the "other" clauses is returned.
+ * </p><p>
+ * An unquoted pound sign (<code>#</code>) in the selected sub-message
+ * itself (i.e., outside of arguments nested in the sub-message)
+ * is replaced by the input number minus the offset.
+ * The number-minus-offset value is formatted using a
+ * <code>NumberFormat</code> for the <code>PluralFormat</code>'s locale. If you
+ * need special number formatting, you have to use a <code>MessageFormat</code>
+ * and explicitly specify a <code>NumberFormat</code> argument.
+ * <strong>Note:</strong> That argument is formatting without subtracting the offset!
+ * If you need a custom format and have a non-zero offset, then you need to pass the
+ * number-minus-offset value as a separate parameter.
+ * </p>
+ * For a usage example, see the {@link MessageFormat} class documentation.
+ *
+ * <h4>Defining Custom Plural Rules</h4>
+ * <p>If you need to use <code>PluralFormat</code> with custom rules, you can
+ * create a <code>PluralRules</code> object and pass it to
+ * <code>PluralFormat</code>'s constructor. If you also specify a locale in this
+ * constructor, this locale will be used to format the number in the message
+ * texts.
+ * </p><p>
+ * For more information about <code>PluralRules</code>, see
+ * {@link PluralRules}.
+ * </p>
+ *
+ * ported from Java
+ * @stable ICU 4.0
+ */
+
+class U_I18N_API PluralFormat : public Format {
+public:
+
+ /**
+ * Creates a new <code>PluralFormat</code> for the default locale.
+ * This locale will be used to get the set of plural rules and for standard
+ * number formatting.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given locale.
+ * @param locale the <code>PluralFormat</code> will be configured with
+ * rules for this locale. This locale will also be used for
+ * standard number formatting.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given set of rules.
+ * The standard number formatting will be done using the default locale.
+ * @param rules defines the behavior of the <code>PluralFormat</code>
+ * object.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const PluralRules& rules, UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given set of rules.
+ * The standard number formatting will be done using the given locale.
+ * @param locale the default number formatting will be done using this
+ * locale.
+ * @param rules defines the behavior of the <code>PluralFormat</code>
+ * object.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const Locale& locale, const PluralRules& rules, UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given pattern string.
+ * The default locale will be used to get the set of plural rules and for
+ * standard number formatting.
+ * @param pattern the pattern for this <code>PluralFormat</code>.
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const UnicodeString& pattern, UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given pattern string and
+ * locale.
+ * The locale will be used to get the set of plural rules and for
+ * standard number formatting.
+ * @param locale the <code>PluralFormat</code> will be configured with
+ * rules for this locale. This locale will also be used for
+ * standard number formatting.
+ * @param pattern the pattern for this <code>PluralFormat</code>.
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const Locale& locale, const UnicodeString& pattern, UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given set of rules, a
+ * pattern and a locale.
+ * @param rules defines the behavior of the <code>PluralFormat</code>
+ * object.
+ * @param pattern the pattern for this <code>PluralFormat</code>.
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const PluralRules& rules,
+ const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Creates a new <code>PluralFormat</code> for a given set of rules, a
+ * pattern and a locale.
+ * @param locale the <code>PluralFormat</code> will be configured with
+ * rules for this locale. This locale will also be used for
+ * standard number formatting.
+ * @param rules defines the behavior of the <code>PluralFormat</code>
+ * object.
+ * @param pattern the pattern for this <code>PluralFormat</code>.
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const Locale& locale,
+ const PluralRules& rules,
+ const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * copy constructor.
+ * @stable ICU 4.0
+ */
+ PluralFormat(const PluralFormat& other);
+
+ /**
+ * Destructor.
+ * @stable ICU 4.0
+ */
+ virtual ~PluralFormat();
+
+ /**
+ * Sets the pattern used by this plural format.
+ * The method parses the pattern and creates a map of format strings
+ * for the plural rules.
+ * Patterns and their interpretation are specified in the class description.
+ *
+ * @param pattern the pattern for this plural format
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ void applyPattern(const UnicodeString& pattern, UErrorCode& status);
+
+
+ using Format::format;
+
+ /**
+ * Formats a plural message for a given number.
+ *
+ * @param number a number for which the plural message should be formatted
+ * for. If no pattern has been applied to this
+ * <code>PluralFormat</code> object yet, the formatted number
+ * will be returned.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @return the string containing the formatted plural message.
+ * @stable ICU 4.0
+ */
+ UnicodeString format(int32_t number, UErrorCode& status) const;
+
+ /**
+ * Formats a plural message for a given number.
+ *
+ * @param number a number for which the plural message should be formatted
+ * for. If no pattern has been applied to this
+ * PluralFormat object yet, the formatted number
+ * will be returned.
+ * @param status output param set to success or failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @return the string containing the formatted plural message.
+ * @stable ICU 4.0
+ */
+ UnicodeString format(double number, UErrorCode& status) const;
+
+ /**
+ * Formats a plural message for a given number.
+ *
+ * @param number a number for which the plural message should be formatted
+ * for. If no pattern has been applied to this
+ * <code>PluralFormat</code> object yet, the formatted number
+ * will be returned.
+ * @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, which
+ * must not indicate a failure before the function call.
+ * @return the string containing the formatted plural message.
+ * @stable ICU 4.0
+ */
+ UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Formats a plural message for a given number.
+ *
+ * @param number a number for which the plural message should be formatted
+ * for. If no pattern has been applied to this
+ * PluralFormat object yet, the formatted number
+ * will be returned.
+ * @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, which
+ * must not indicate a failure before the function call.
+ * @return the string containing the formatted plural message.
+ * @stable ICU 4.0
+ */
+ UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Sets the locale used by this <code>PluraFormat</code> object.
+ * Note: Calling this method resets this <code>PluraFormat</code> object,
+ * i.e., a pattern that was applied previously will be removed,
+ * and the NumberFormat is set to the default number format for
+ * the locale. The resulting format behaves the same as one
+ * constructed from {@link #PluralFormat(const Locale& locale, UErrorCode& status)}.
+ * @param locale the <code>locale</code> to use to configure the formatter.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ void setLocale(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Sets the number format used by this formatter. You only need to
+ * call this if you want a different number format than the default
+ * formatter for the locale.
+ * @param format the number format to use.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.0
+ */
+ void setNumberFormat(const NumberFormat* format, UErrorCode& status);
+
+ /**
+ * Assignment operator
+ *
+ * @param other the PluralFormat object to copy from.
+ * @stable ICU 4.0
+ */
+ PluralFormat& operator=(const PluralFormat& other);
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the PluralFormat object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @stable ICU 4.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the PluralFormat object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @stable ICU 4.0
+ */
+ virtual UBool operator!=(const Format& other) const;
+
+ /**
+ * Clones this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ * @stable ICU 4.0
+ */
+ virtual Format* clone(void) 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 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 4.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Returns the pattern from applyPattern() or constructor().
+ *
+ * @param appendTo output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return the UnicodeString with inserted pattern.
+ * @stable ICU 4.0
+ */
+ UnicodeString& toPattern(UnicodeString& appendTo);
+
+ /**
+ * This method is not yet supported by <code>PluralFormat</code>.
+ * <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.
+ * @stable ICU 4.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 4.0
+ *
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 4.0
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ private:
+
+ /**
+ * @internal
+ */
+ class U_I18N_API PluralSelector : public UMemory {
+ public:
+ /**
+ * Given a number, returns the appropriate PluralFormat keyword.
+ *
+ * @param number The number to be plural-formatted.
+ * @param ec Error code.
+ * @return The selected PluralFormat keyword.
+ */
+ virtual UnicodeString select(double number, UErrorCode& ec) const = 0;
+ };
+
+ /**
+ * @internal
+ */
+ class U_I18N_API PluralSelectorAdapter : public PluralSelector {
+ public:
+ PluralSelectorAdapter() : pluralRules(NULL) {
+ }
+
+ virtual ~PluralSelectorAdapter();
+
+ virtual UnicodeString select(double number, UErrorCode& /*ec*/) const;
+
+ void reset();
+
+ PluralRules* pluralRules;
+ };
+
+ Locale locale;
+ MessagePattern msgPattern;
+ NumberFormat* numberFormat;
+ double offset;
+ PluralSelectorAdapter pluralRulesWrapper;
+
+ PluralFormat(); // default constructor not implemented
+ void init(const PluralRules* rules, UErrorCode& status);
+ /**
+ * Copies dynamically allocated values (pointer fields).
+ * Others are copied using their copy constructors and assignment operators.
+ */
+ void copyObjects(const PluralFormat& other);
+
+ /**
+ * Finds the PluralFormat sub-message for the given number, or the "other" sub-message.
+ * @param pattern A MessagePattern.
+ * @param partIndex the index of the first PluralFormat argument style part.
+ * @param selector the PluralSelector for mapping the number (minus offset) to a keyword.
+ * @param number a number to be matched to one of the PluralFormat argument's explicit values,
+ * or mapped via the PluralSelector.
+ * @param ec ICU error code.
+ * @return the sub-message start part index.
+ */
+ static int32_t findSubMessage(
+ const MessagePattern& pattern, int32_t partIndex,
+ const PluralSelector& selector, double number, UErrorCode& ec);
+
+ friend class MessageFormat;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _PLURFMT
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurrule.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurrule.h
new file mode 100644
index 00000000000..ee281ea88f1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/plurrule.h
@@ -0,0 +1,381 @@
+/*
+*******************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+*
+* File PLURRULE.H
+*
+* Modification History:*
+* Date Name Description
+*
+********************************************************************************
+*/
+
+#ifndef PLURRULE
+#define PLURRULE
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: PluralRules object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+
+/**
+ * Value returned by PluralRules::getUniqueKeywordValue() when there is no
+ * unique value to return.
+ * @draft ICU 4.8
+ */
+#define UPLRULES_NO_UNIQUE_VALUE ((double)-0.00123456777)
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+class RuleChain;
+class RuleParser;
+class PluralKeywordEnumeration;
+
+/**
+ * Defines rules for mapping non-negative numeric values onto a small set of
+ * keywords. Rules are constructed from a text description, consisting
+ * of a series of keywords and conditions. The {@link #select} method
+ * examines each condition in order and returns the keyword for the
+ * first condition that matches the number. If none match,
+ * default rule(other) is returned.
+ *
+ * For more information, details, and tips for writing rules, see the
+ * LDML spec, C.11 Language Plural Rules:
+ * http://www.unicode.org/draft/reports/tr35/tr35.html#Language_Plural_Rules
+ *
+ * Examples:<pre>
+ * "one: n is 1; few: n in 2..4"</pre>
+ * This defines two rules, for 'one' and 'few'. The condition for
+ * 'one' is "n is 1" which means that the number must be equal to
+ * 1 for this condition to pass. The condition for 'few' is
+ * "n in 2..4" which means that the number must be between 2 and
+ * 4 inclusive for this condition to pass. All other numbers
+ * are assigned the keyword "other" by the default rule.
+ * </p><pre>
+ * "zero: n is 0; one: n is 1; zero: n mod 100 in 1..19"</pre>
+ * This illustrates that the same keyword can be defined multiple times.
+ * Each rule is examined in order, and the first keyword whose condition
+ * passes is the one returned. Also notes that a modulus is applied
+ * to n in the last rule. Thus its condition holds for 119, 219, 319...
+ * </p><pre>
+ * "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14"</pre>
+ * This illustrates conjunction and negation. The condition for 'few'
+ * has two parts, both of which must be met: "n mod 10 in 2..4" and
+ * "n mod 100 not in 12..14". The first part applies a modulus to n
+ * before the test as in the previous example. The second part applies
+ * a different modulus and also uses negation, thus it matches all
+ * numbers _not_ in 12, 13, 14, 112, 113, 114, 212, 213, 214...
+ * </p>
+ * <p>
+ * Syntax:<pre>
+ * \code
+ * rules = rule (';' rule)*
+ * rule = keyword ':' condition
+ * keyword = <identifier>
+ * condition = and_condition ('or' and_condition)*
+ * and_condition = relation ('and' relation)*
+ * relation = is_relation | in_relation | within_relation | 'n' <EOL>
+ * is_relation = expr 'is' ('not')? value
+ * in_relation = expr ('not')? 'in' range_list
+ * within_relation = expr ('not')? 'within' range
+ * expr = 'n' ('mod' value)?
+ * range_list = (range | value) (',' range_list)*
+ * value = digit+
+ * digit = 0|1|2|3|4|5|6|7|8|9
+ * range = value'..'value
+ * \endcode
+ * </pre></p>
+ * <p>
+ * An "identifier" is a sequence of characters that do not have the
+ * Unicode Pattern_Syntax or Pattern_White_Space properties.
+ * <p>
+ * The difference between 'in' and 'within' is that 'in' only includes
+ * integers in the specified range, while 'within' includes all values.</p>
+ * <p>
+ * Keywords
+ * could be defined by users or from ICU locale data. There are 6
+ * predefined values in ICU - 'zero', 'one', 'two', 'few', 'many' and
+ * 'other'. Callers need to check the value of keyword returned by
+ * {@link #select} method.
+ * </p>
+ *
+ * Examples:<pre>
+ * UnicodeString keyword = pl->select(number);
+ * if (keyword== UnicodeString("one") {
+ * ...
+ * }
+ * else if ( ... )
+ * </pre>
+ * <strong>Note:</strong><br>
+ * <p>
+ * ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>.
+ * For these predefined rules, see CLDR page at
+ * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
+ * </p>
+ */
+class U_I18N_API PluralRules : public UObject {
+public:
+
+ /**
+ * Constructor.
+ * @param status Output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ *
+ * @stable ICU 4.0
+ */
+ PluralRules(UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.0
+ */
+ PluralRules(const PluralRules& other);
+
+ /**
+ * Destructor.
+ * @stable ICU 4.0
+ */
+ virtual ~PluralRules();
+
+ /**
+ * Clone
+ * @stable ICU 4.0
+ */
+ PluralRules* clone() const;
+
+ /**
+ * Assignment operator.
+ * @stable ICU 4.0
+ */
+ PluralRules& operator=(const PluralRules&);
+
+ /**
+ * Creates a PluralRules from a description if it is parsable, otherwise
+ * returns NULL.
+ *
+ * @param description rule description
+ * @param status Output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @return new PluralRules pointer. NULL if there is an error.
+ * @stable ICU 4.0
+ */
+ static PluralRules* U_EXPORT2 createRules(const UnicodeString& description,
+ UErrorCode& status);
+
+ /**
+ * The default rules that accept any number.
+ *
+ * @param status Output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @return new PluralRules pointer. NULL if there is an error.
+ * @stable ICU 4.0
+ */
+ static PluralRules* U_EXPORT2 createDefaultRules(UErrorCode& status);
+
+ /**
+ * Provides access to the predefined <code>PluralRules</code> for a given
+ * locale.
+ *
+ * @param locale The locale for which a <code>PluralRules</code> object is
+ * returned.
+ * @param status Output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @return The predefined <code>PluralRules</code> object pointer for
+ * this locale. If there's no predefined rules for this locale,
+ * the rules for the closest parent in the locale hierarchy
+ * that has one will be returned. The final fallback always
+ * returns the default 'other' rules.
+ * @stable ICU 4.0
+ */
+ static PluralRules* U_EXPORT2 forLocale(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Given a number, returns the keyword of the first rule that applies to
+ * the number. This function can be used with isKeyword* functions to
+ * determine the keyword for default plural rules.
+ *
+ * @param number The number for which the rule has to be determined.
+ * @return The keyword of the selected rule.
+ * @stable ICU 4.0
+ */
+ UnicodeString select(int32_t number) const;
+
+ /**
+ * Given a number, returns the keyword of the first rule that applies to
+ * the number. This function can be used with isKeyword* functions to
+ * determine the keyword for default plural rules.
+ *
+ * @param number The number for which the rule has to be determined.
+ * @return The keyword of the selected rule.
+ * @stable ICU 4.0
+ */
+ UnicodeString select(double number) const;
+
+ /**
+ * Returns a list of all rule keywords used in this <code>PluralRules</code>
+ * object. The rule 'other' is always present by default.
+ *
+ * @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 keywords.
+ * The caller must delete the object.
+ * @stable ICU 4.0
+ */
+ StringEnumeration* getKeywords(UErrorCode& status) const;
+
+ /**
+ * Returns a unique value for this keyword if it exists, else the constant
+ * UPLRULES_NO_UNIQUE_VALUE.
+ *
+ * @param keyword The keyword.
+ * @return The unique value that generates the keyword, or
+ * UPLRULES_NO_UNIQUE_VALUE if the keyword is undefined or there is no
+ * unique value that generates this keyword.
+ * @draft ICU 4.8
+ */
+ double getUniqueKeywordValue(const UnicodeString& keyword);
+
+ /**
+ * Returns all the values for which select() would return the keyword. If
+ * the keyword is unknown, returns no values, but this is not an error. If
+ * the number of values is unlimited, returns no values and -1 as the
+ * count.
+ *
+ * The number of returned values is typically small.
+ *
+ * @param keyword The keyword.
+ * @param dest Array into which to put the returned values. May
+ * be NULL if destCapacity is 0.
+ * @param destCapacity The capacity of the array, must be at least 0.
+ * @param status The error code.
+ * @return The count of values available, or -1. This count
+ * can be larger than destCapacity, but no more than
+ * destCapacity values will be written.
+ * @draft ICU 4.8
+ */
+ int32_t getAllKeywordValues(const UnicodeString &keyword,
+ double *dest, int32_t destCapacity,
+ UErrorCode& status);
+
+ /**
+ * Returns sample values for which select() would return the keyword. If
+ * the keyword is unknown, returns no values, but this is not an error.
+ *
+ * The number of returned values is typically small.
+ *
+ * @param keyword The keyword.
+ * @param dest Array into which to put the returned values. May
+ * be NULL if destCapacity is 0.
+ * @param destCapacity The capacity of the array, must be at least 0.
+ * @param status The error code.
+ * @return The count of values written.
+ * If more than destCapacity samples are available, then
+ * only destCapacity are written, and destCapacity is returned as the count,
+ * rather than setting a U_BUFFER_OVERFLOW_ERROR.
+ * (The actual number of keyword values could be unlimited.)
+ * @draft ICU 4.8
+ */
+ int32_t getSamples(const UnicodeString &keyword,
+ double *dest, int32_t destCapacity,
+ UErrorCode& status);
+
+ /**
+ * Returns TRUE if the given keyword is defined in this
+ * <code>PluralRules</code> object.
+ *
+ * @param keyword the input keyword.
+ * @return TRUE if the input keyword is defined.
+ * Otherwise, return FALSE.
+ * @stable ICU 4.0
+ */
+ UBool isKeyword(const UnicodeString& keyword) const;
+
+
+ /**
+ * Returns keyword for default plural form.
+ *
+ * @return keyword for default plural form.
+ * @internal 4.0
+ * @stable ICU 4.0
+ */
+ UnicodeString getKeywordOther() const;
+
+ /**
+ * Compares the equality of two PluralRules objects.
+ *
+ * @param other The other PluralRules object to be compared with.
+ * @return True if the given PluralRules is the same as this
+ * PluralRules; false otherwise.
+ * @stable ICU 4.0
+ */
+ virtual UBool operator==(const PluralRules& other) const;
+
+ /**
+ * Compares the inequality of two PluralRules objects.
+ *
+ * @param other The PluralRules object to be compared with.
+ * @return True if the given PluralRules is not the same as this
+ * PluralRules; false otherwise.
+ * @stable ICU 4.0
+ */
+ UBool operator!=(const PluralRules& other) const {return !operator==(other);}
+
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 4.0
+ *
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 4.0
+ */
+ virtual UClassID getDynamicClassID() const;
+
+
+private:
+ RuleChain *mRules;
+ RuleParser *mParser;
+ double *mSamples;
+ int32_t *mSampleInfo;
+ int32_t mSampleInfoCount;
+
+ PluralRules(); // default constructor not implemented
+ int32_t getRepeatLimit() const;
+ void parseDescription(UnicodeString& ruleData, RuleChain& rules, UErrorCode &status);
+ void getNextLocale(const UnicodeString& localeData, int32_t* curIndex, UnicodeString& localeName);
+ void addRules(RuleChain& rules);
+ int32_t getNumberValue(const UnicodeString& token) const;
+ UnicodeString getRuleFromResource(const Locale& locale, UErrorCode& status);
+
+ static const int32_t MAX_SAMPLES = 3;
+
+ int32_t getSamplesInternal(const UnicodeString &keyword, double *dest,
+ int32_t destCapacity, UBool includeUnlimited,
+ UErrorCode& status);
+ int32_t getKeywordIndex(const UnicodeString& keyword,
+ UErrorCode& status) const;
+ void initSamples(UErrorCode& status);
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _PLURRULE
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbnf.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbnf.h
new file mode 100644
index 00000000000..59835d39405
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbnf.h
@@ -0,0 +1,1059 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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_NUMBERING_SYSTEM,
+ 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 four 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"),
+ * URBNF_DURATION, which formats a duration in seconds as hours, minutes, and seconds,
+ * and URBNF_NUMBERING_SYSTEM, which is used to invoke rules for alternate numbering
+ * systems such as the Hebrew numbering system, or for Roman Numerals, etc.
+ * @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());
+
+
+ using NumberFormat::format;
+
+ /**
+ * 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;
+
+ // Temporary workaround - when noParse is true, do noting in parse.
+ // TODO: We need a real fix - see #6895/#6896
+ UBool noParse;
+};
+
+// ---------------
+
+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-4.8.1/i18n/unicode/rbtz.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbtz.h
new file mode 100644
index 00000000000..2be29670cbf
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/rbtz.h
@@ -0,0 +1,361 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, 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;
+
+/**
+ * a BasicTimeZone subclass implemented in terms of InitialTimeZoneRule and TimeZoneRule instances
+ * @see BasicTimeZone
+ * @see InitialTimeZoneRule
+ * @see TimeZoneRule
+ */
+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.
+ * @stable ICU 3.8
+ */
+ RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule);
+
+ /**
+ * Copy constructor.
+ * @param source The RuleBasedTimeZone object to be copied.
+ * @stable ICU 3.8
+ */
+ RuleBasedTimeZone(const RuleBasedTimeZone& source);
+
+ /**
+ * Destructor.
+ * @stable ICU 3.8
+ */
+ virtual ~RuleBasedTimeZone();
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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-4.8.1/i18n/unicode/regex.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/regex.h
new file mode 100644
index 00000000000..0b1f2ee2220
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/regex.h
@@ -0,0 +1,1861 @@
+/*
+**********************************************************************
+* Copyright (C) 2002-2011, 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/utext.h"
+#include "unicode/parseerr.h"
+
+#include "unicode/uregex.h"
+
+U_NAMESPACE_BEGIN
+
+
+// Forward Declarations...
+
+class RegexMatcher;
+class RegexPattern;
+class UVector;
+class UVector32;
+class UVector64;
+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
+ #undef RegexPatternDump
+ #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. 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. Note, the text referred
+ * to by this UText must not be deleted during the lifetime of the
+ * RegexPattern object or any RegexMatcher object created from it.
+ * @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.
+ *
+ * @draft ICU 4.6
+ */
+ static RegexPattern * U_EXPORT2 compile( UText *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 numbers) 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. Note, the text referred
+ * to by this UText must not be deleted during the lifetime of the
+ * RegexPattern object or any RegexMatcher object created from it.
+ * @param flags The match mode flags to be used.
+ * @param pe Receives the position (line and column numbers) 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.
+ *
+ * @draft ICU 4.6
+ */
+ static RegexPattern * U_EXPORT2 compile( UText *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);
+
+
+ /**
+ * 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. Note, the text referred
+ * to by this UText must not be deleted during the lifetime of the
+ * RegexPattern object or any RegexMatcher object created from it.
+ * @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.
+ *
+ * @draft ICU 4.6
+ */
+ static RegexPattern * U_EXPORT2 compile( UText *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 accidentally 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>
+ * or in a UText, using
+ * <code>utext_openUChars(UText *ut, const UChar *text, int64_t textLength, UErrorCode *status);</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 regular 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);
+
+
+ /**
+ * Test whether a string matches a regular expression. This convenience function
+ * both compiles the regular 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.
+ *
+ * @draft ICU 4.6
+ */
+ static UBool U_EXPORT2 matches(UText *regex,
+ UText *input,
+ UParseError &pe,
+ UErrorCode &status);
+
+
+ /**
+ * Returns the regular expression from which this pattern was compiled. This method will work
+ * even if the pattern was compiled from a UText.
+ *
+ * Note: If the pattern was originally compiled from a UText, and that UText was modified,
+ * the returned string may no longer reflect the RegexPattern object.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString pattern() const;
+
+
+ /**
+ * Returns the regular expression from which this pattern was compiled. This method will work
+ * even if the pattern was compiled from a UnicodeString.
+ *
+ * Note: This is the original input, not a clone. If the pattern was originally compiled from a
+ * UText, and that UText was modified, the returned UText may no longer reflect the RegexPattern
+ * object.
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *patternText(UErrorCode &status) const;
+
+
+ /**
+ * Split a string into fields. Somewhat like split() from Perl or Java.
+ * Pattern matches identify delimiters that separate the input
+ * into fields. The input data between the delimiters becomes the
+ * fields themselves.
+ *
+ * If the delimiter pattern includes capture groups, the captured text will
+ * also appear in the destination array of output strings, interspersed
+ * with the fields. This is similar to Perl, but differs from Java,
+ * which ignores the presence of capture groups in the pattern.
+ *
+ * Trailing empty fields will always be returned, assuming sufficient
+ * destination capacity. This differs from the default behavior for Java
+ * and Perl where trailing empty fields are not returned.
+ *
+ * The number of strings produced by the split operation is returned.
+ * This count includes the strings from capture groups in the delimiter pattern.
+ * This behavior differs from Java, which ignores capture groups.
+ *
+ * For the best performance on split() operations,
+ * <code>RegexMatcher::split</code> is preferable 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;
+
+
+ /**
+ * Split a string into fields. Somewhat like split() from Perl or Java.
+ * Pattern matches identify delimiters that separate the input
+ * into fields. The input data between the delimiters becomes the
+ * fields themselves.
+ *
+ * If the delimiter pattern includes capture groups, the captured text will
+ * also appear in the destination array of output strings, interspersed
+ * with the fields. This is similar to Perl, but differs from Java,
+ * which ignores the presence of capture groups in the pattern.
+ *
+ * Trailing empty fields will always be returned, assuming sufficient
+ * destination capacity. This differs from the default behavior for Java
+ * and Perl where trailing empty fields are not returned.
+ *
+ * The number of strings produced by the split operation is returned.
+ * This count includes the strings from capture groups in the delimiter pattern.
+ * This behavior differs from Java, which ignores capture groups.
+ *
+ * For the best performance on split() operations,
+ * <code>RegexMatcher::split</code> is preferable 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 mutable UText structs to receive the results of the split.
+ * If a field is NULL, a new UText is allocated to contain the results for
+ * that field. This new UText is not guaranteed to be mutable.
+ * @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 destination strings used.
+ *
+ * @draft ICU 4.6
+ */
+ virtual int32_t split(UText *input,
+ UText *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
+ //
+ UText *fPattern; // The original pattern string.
+ UnicodeString *fPatternString; // The original pattern UncodeString if relevant
+ uint32_t fFlags; // The flags used when compiling the pattern.
+ //
+ UVector64 *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;
+ UBool fNeedsAltInput;
+
+ 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 regular 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.
+ *
+ * @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.
+ *
+ * @draft ICU 4.6
+ */
+ RegexMatcher(UText *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);
+
+ /**
+ * 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 make a shallow clone of the supplied input text, and all regexp
+ * pattern matching operations happen on this clone. While read-only operations on
+ * the supplied text are permitted, it is critical that the underlying 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 shallow clone of the text.
+ * @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.
+ *
+ * @draft ICU 4.6
+ */
+ RegexMatcher(UText *regexp, UText *input,
+ uint32_t flags, UErrorCode &status);
+
+private:
+ /**
+ * Cause a compilation error if an application accidentally 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>
+ * or in a UText, using
+ * <code>utext_openUChars(UText *ut, const UChar *text, int64_t textLength, UErrorCode *status);</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 region 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);
+
+
+ /**
+ * Resets the matcher, then attempts to match the input beginning
+ * at the specified startIndex, and extending to the end of the input.
+ * The input region is reset to include the entire input string.
+ * A successful match must extend to the end of the input.
+ * @param startIndex The input string (native) 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(int64_t startIndex, UErrorCode &status);
+
+
+ /**
+ * Attempts to match the input string, starting from the beginning of the region,
+ * against the pattern. Like the matches() method, this function
+ * always starts at the beginning of the input region;
+ * unlike that function, it does not require that the entire region 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 (native) 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(int64_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 (native) index 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(int64_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 a shallow clone of the entire live input string with the UText current native index
+ * set to the beginning of the requested group.
+ *
+ * @param dest The UText into which the input should be cloned, or NULL to create a new UText
+ * @param group_len A reference to receive the length of the desired capture group
+ * @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 dest if non-NULL, a shallow copy of the input text otherwise
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *group(UText *dest, int64_t &group_len, UErrorCode &status) const;
+
+ /**
+ * Returns a shallow clone of the entire live input string with the UText current native index
+ * set to the beginning of the requested group.
+ *
+ * @param groupNum The capture group number.
+ * @param dest The UText into which the input should be cloned, or NULL to create a new UText.
+ * @param group_len A reference to receive the length of the desired capture group
+ * @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 dest if non-NULL, a shallow copy of the input text otherwise
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *group(int32_t groupNum, UText *dest, int64_t &group_len, 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 dest A mutable UText in which the matching text is placed.
+ * If NULL, a new UText will be created (which may not be mutable).
+ * @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. If a pre-allocated UText
+ * was provided, it will always be used and returned.
+ *
+ * @internal ICU 4.4 technology preview
+ */
+ virtual UText *group(int32_t groupNum, UText *dest, UErrorCode &status) 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 (native) 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
+ * during the previous match operation.
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return The (native) position in the input string of the start of the last match.
+ * @draft ICU 4.6
+ */
+ virtual int64_t start64(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 (native) 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 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 (native) start position of substring matched by the specified group.
+ * @draft ICU 4.6
+ */
+ virtual int64_t start64(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.
+ * The index value returned is a native index, corresponding to
+ * code units for the underlying encoding type, for example,
+ * a byte index for UTF-8.
+ * @stable ICU 2.4
+ */
+ virtual int32_t end(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.
+ * The index value returned is a native index, corresponding to
+ * code units for the underlying encoding type, for example,
+ * a byte index for UTF-8.
+ * @draft ICU 4.6
+ */
+ virtual int64_t end64(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 specified group during the previous match operation.
+ * Return -1 if the capture group exists in the pattern but was not part of the match.
+ * The index value returned is a native index, corresponding to
+ * code units for the underlying encoding type, for example,
+ * a byte index for UTF8.
+ * @stable ICU 2.4
+ */
+ virtual int32_t end(int32_t group, 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 specified group during the previous match operation.
+ * Return -1 if the capture group exists in the pattern but was not part of the match.
+ * The index value returned is a native index, corresponding to
+ * code units for the underlying encoding type, for example,
+ * a byte index for UTF8.
+ * @draft ICU 4.6
+ */
+ virtual int64_t end64(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 (native) position in the input string.
+ * <p>
+ * The matcher's region is reset to its default, which is the entire
+ * input string.
+ * <p>
+ * An alternative to this function is to set a match region
+ * beginning at the desired index.
+ *
+ * @return this RegexMatcher.
+ * @stable ICU 2.8
+ */
+ virtual RegexMatcher &reset(int64_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.
+ * Note that while a reset on the matcher with an input string that is then
+ * modified across/during matcher operations may be supported currently for UnicodeString,
+ * this was not originally intended behavior, and support for this is not guaranteed
+ * in upcoming versions of ICU.
+ * @return this RegexMatcher.
+ * @stable ICU 2.4
+ */
+ virtual RegexMatcher &reset(const UnicodeString &input);
+
+
+ /**
+ * 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 makes a shallow clone of the given text; ownership of the
+ * original string remains with the caller. Because no deep copy of the
+ * text is made, it is essential that the caller not modify the string
+ * until after regexp operations on it are done.
+ * @return this RegexMatcher.
+ *
+ * @draft ICU 4.6
+ */
+ virtual RegexMatcher &reset(UText *input);
+
+
+ /**
+ * Set the subject text string upon which the regular expression is looking for matches
+ * without changing any other aspect of the matching state.
+ * The new and previous text strings must have the same content.
+ *
+ * This function is intended for use in environments where ICU is operating on
+ * strings that may move around in memory. It provides a mechanism for notifying
+ * ICU that the string has been relocated, and providing a new UText to access the
+ * string in its new position.
+ *
+ * Note that the regular expression implementation never copies the underlying text
+ * of a string being matched, but always operates directly on the original text
+ * provided by the user. Refreshing simply drops the references to the old text
+ * and replaces them with references to the new.
+ *
+ * Caution: this function is normally used only by very specialized,
+ * system-level code. One example use case is with garbage collection that moves
+ * the text in memory.
+ *
+ * @param input The new (moved) text string.
+ * @param status Receives errors detected by this function.
+ *
+ * @draft ICU 4.8
+ */
+ virtual RegexMatcher &refreshInputText(UText *input, UErrorCode &status);
+
+private:
+ /**
+ * Cause a compilation error if an application accidentally 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>
+ * or in a UText, using
+ * <code>utext_openUChars(UText *ut, const UChar *text, int64_t textLength, UErrorCode *status);</code>
+ *
+ * @internal
+ */
+ RegexMatcher &reset(const UChar *input);
+public:
+
+ /**
+ * Returns the input string being matched. Ownership of the string belongs to
+ * the matcher; it should not be altered or deleted. This method will work even if the input
+ * was originally supplied as a UText.
+ * @return the input string
+ * @stable ICU 2.4
+ */
+ virtual const UnicodeString &input() const;
+
+ /**
+ * Returns the input string being matched. This is the live input text; it should not be
+ * altered or deleted. This method will work even if the input was originally supplied as
+ * a UnicodeString.
+ * @return the input text
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *inputText() const;
+
+ /**
+ * Returns the input string being matched, either by copying it into the provided
+ * UText parameter or by returning a shallow clone of the live input. Note that copying
+ * the entire input may cause significant performance and memory issues.
+ * @param dest The UText into which the input should be copied, or NULL to create a new UText
+ * @param status error code
+ * @return dest if non-NULL, a shallow copy of the input text otherwise
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *getInput(UText *dest, UErrorCode &status) const;
+
+
+ /** Sets the limits of this matcher's region.
+ * The region is the part of the input string that will be searched to find a match.
+ * Invoking this method resets the matcher, and then sets the region to start
+ * at the index specified by the start parameter and end at the index specified
+ * by the end parameter.
+ *
+ * Depending on the transparency and anchoring being used (see useTransparentBounds
+ * and useAnchoringBounds), certain constructs such as anchors may behave differently
+ * at or around the boundaries of the region
+ *
+ * The function will fail if start is greater than limit, or if either index
+ * is less than zero or greater than the length of the string being matched.
+ *
+ * @param start The (native) index to begin searches at.
+ * @param limit The index to end searches at (exclusive).
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+ virtual RegexMatcher &region(int64_t start, int64_t limit, UErrorCode &status);
+
+ /**
+ * Identical to region(start, limit, status) but also allows a start position without
+ * resetting the region state.
+ * @param regionStart The region start
+ * @param regionLimit the limit of the region
+ * @param startIndex The (native) index within the region bounds at which to begin searches.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * If startIndex is not within the specified region bounds,
+ * U_INDEX_OUTOFBOUNDS_ERROR is returned.
+ * @draft ICU 4.6
+ */
+ virtual RegexMatcher &region(int64_t regionStart, int64_t regionLimit, int64_t startIndex, UErrorCode &status);
+
+ /**
+ * Reports the start index of this matcher's region. The searches this matcher
+ * conducts are limited to finding matches within regionStart (inclusive) and
+ * regionEnd (exclusive).
+ *
+ * @return The starting (native) index of this matcher's region.
+ * @stable ICU 4.0
+ */
+ virtual int32_t regionStart() const;
+
+ /**
+ * Reports the start index of this matcher's region. The searches this matcher
+ * conducts are limited to finding matches within regionStart (inclusive) and
+ * regionEnd (exclusive).
+ *
+ * @return The starting (native) index of this matcher's region.
+ * @draft ICU 4.6
+ */
+ virtual int64_t regionStart64() const;
+
+
+ /**
+ * Reports the end (limit) index (exclusive) of this matcher's region. The searches
+ * this matcher conducts are limited to finding matches within regionStart
+ * (inclusive) and regionEnd (exclusive).
+ *
+ * @return The ending point (native) of this matcher's region.
+ * @stable ICU 4.0
+ */
+ virtual int32_t regionEnd() const;
+
+ /**
+ * Reports the end (limit) index (exclusive) of this matcher's region. The searches
+ * this matcher conducts are limited to finding matches within regionStart
+ * (inclusive) and regionEnd (exclusive).
+ *
+ * @return The ending point (native) of this matcher's region.
+ * @draft ICU 4.6
+ */
+ virtual int64_t regionEnd64() const;
+
+ /**
+ * Queries the transparency of region bounds for this matcher.
+ * See useTransparentBounds for a description of transparent and opaque bounds.
+ * By default, a matcher uses opaque region boundaries.
+ *
+ * @return TRUE if this matcher is using opaque bounds, false if it is not.
+ * @stable ICU 4.0
+ */
+ virtual UBool hasTransparentBounds() const;
+
+ /**
+ * Sets the transparency of region bounds for this matcher.
+ * Invoking this function with an argument of true will set this matcher to use transparent bounds.
+ * If the boolean argument is false, then opaque bounds will be used.
+ *
+ * Using transparent bounds, the boundaries of this matcher's region are transparent
+ * to lookahead, lookbehind, and boundary matching constructs. Those constructs can
+ * see text beyond the boundaries of the region while checking for a match.
+ *
+ * With opaque bounds, no text outside of the matcher's region is visible to lookahead,
+ * lookbehind, and boundary matching constructs.
+ *
+ * By default, a matcher uses opaque bounds.
+ *
+ * @param b TRUE for transparent bounds; FALSE for opaque bounds
+ * @return This Matcher;
+ * @stable ICU 4.0
+ **/
+ virtual RegexMatcher &useTransparentBounds(UBool b);
+
+
+ /**
+ * Return true if this matcher is using anchoring bounds.
+ * By default, matchers use anchoring region bounds.
+ *
+ * @return TRUE if this matcher is using anchoring bounds.
+ * @stable ICU 4.0
+ */
+ virtual UBool hasAnchoringBounds() const;
+
+
+ /**
+ * Set whether this matcher is using Anchoring Bounds for its region.
+ * With anchoring bounds, pattern anchors such as ^ and $ will match at the start
+ * and end of the region. Without Anchoring Bounds, anchors will only match at
+ * the positions they would in the complete text.
+ *
+ * Anchoring Bounds are the default for regions.
+ *
+ * @param b TRUE if to enable anchoring bounds; FALSE to disable them.
+ * @return This Matcher
+ * @stable ICU 4.0
+ */
+ virtual RegexMatcher &useAnchoringBounds(UBool b);
+
+
+ /**
+ * Return TRUE if the most recent matching operation touched the
+ * end of the text being processed. In this case, additional input text could
+ * change the results of that match.
+ *
+ * hitEnd() is defined for both successful and unsuccessful matches.
+ * In either case hitEnd() will return TRUE if if the end of the text was
+ * reached at any point during the matching process.
+ *
+ * @return TRUE if the most recent match hit the end of input
+ * @stable ICU 4.0
+ */
+ virtual UBool hitEnd() const;
+
+ /**
+ * Return TRUE the most recent match succeeded and additional input could cause
+ * it to fail. If this method returns false and a match was found, then more input
+ * might change the match but the match won't be lost. If a match was not found,
+ * then requireEnd has no meaning.
+ *
+ * @return TRUE if more input could cause the most recent match to no longer match.
+ * @stable ICU 4.0
+ */
+ virtual UBool requireEnd() 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 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 dest a mutable UText in which the results are placed.
+ * If NULL, a new UText will be created (which may not be mutable).
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return a string containing the results of the find and replace.
+ * If a pre-allocated UText was provided, it will always be used and returned.
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *replaceAll(UText *replacement, UText *dest, 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);
+
+
+ /**
+ * 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 dest a mutable UText in which the results are placed.
+ * If NULL, a new UText will be created (which may not be mutable).
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return a string containing the results of the find and replace.
+ * If a pre-allocated UText was provided, it will always be used and returned.
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *replaceFirst(UText *replacement, UText *dest, 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);
+
+
+ /**
+ * 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 mutable UText to which the results of the find-and-replace are appended.
+ * Must not be NULL.
+ * @param replacement A UText 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
+ *
+ * @draft ICU 4.6
+ */
+ virtual RegexMatcher &appendReplacement(UText *dest,
+ UText *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);
+
+
+ /**
+ * 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 mutable UText to which the results of the find-and-replace are appended.
+ * Must not be NULL.
+ * @param status error cod
+ * @return the destination string.
+ *
+ * @draft ICU 4.6
+ */
+ virtual UText *appendTail(UText *dest, 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.
+ *
+ * @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);
+
+
+ /**
+ * 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.
+ *
+ * @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 mutable UText structs to receive the results of the split.
+ * If a field is NULL, a new UText is allocated to contain the results for
+ * that field. This new UText is not guaranteed to be mutable.
+ * @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.
+ *
+ * @draft ICU 4.6
+ */
+ virtual int32_t split(UText *input,
+ UText *dest[],
+ int32_t destCapacity,
+ UErrorCode &status);
+
+ /**
+ * Set a processing time limit for match operations with this Matcher.
+ *
+ * Some patterns, when matching certain strings, can run in exponential time.
+ * For practical purposes, the match operation may appear to be in an
+ * infinite loop.
+ * When a limit is set a match operation will fail with an error if the
+ * limit is exceeded.
+ * <p>
+ * The units of the limit are steps of the match engine.
+ * Correspondence with actual processor time will depend on the speed
+ * of the processor and the details of the specific pattern, but will
+ * typically be on the order of milliseconds.
+ * <p>
+ * By default, the matching time is not limited.
+ * <p>
+ *
+ * @param limit The limit value, or 0 for no limit.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+ virtual void setTimeLimit(int32_t limit, UErrorCode &status);
+
+ /**
+ * Get the time limit, if any, for match operations made with this Matcher.
+ *
+ * @return the maximum allowed time for a match, in units of processing steps.
+ * @stable ICU 4.0
+ */
+ virtual int32_t getTimeLimit() const;
+
+ /**
+ * Set the amount of heap storage available for use by the match backtracking stack.
+ * The matcher is also reset, discarding any results from previous matches.
+ * <p>
+ * ICU uses a backtracking regular expression engine, with the backtrack stack
+ * maintained on the heap. This function sets the limit to the amount of memory
+ * that can be used for this purpose. A backtracking stack overflow will
+ * result in an error from the match operation that caused it.
+ * <p>
+ * A limit is desirable because a malicious or poorly designed pattern can use
+ * excessive memory, potentially crashing the process. A limit is enabled
+ * by default.
+ * <p>
+ * @param limit The maximum size, in bytes, of the matching backtrack stack.
+ * A value of zero means no limit.
+ * The limit must be greater or equal to zero.
+ *
+ * @param status A reference to a UErrorCode to receive any errors.
+ *
+ * @stable ICU 4.0
+ */
+ virtual void setStackLimit(int32_t limit, UErrorCode &status);
+
+ /**
+ * Get the size of the heap storage available for use by the back tracking stack.
+ *
+ * @return the maximum backtracking stack size, in bytes, or zero if the
+ * stack size is unlimited.
+ * @stable ICU 4.0
+ */
+ virtual int32_t getStackLimit() const;
+
+
+ /**
+ * Set a callback function for use with this Matcher.
+ * During matching operations the function will be called periodically,
+ * giving the application the opportunity to terminate a long-running
+ * match.
+ *
+ * @param callback A pointer to the user-supplied callback function.
+ * @param context User context pointer. The value supplied at the
+ * time the callback function is set will be saved
+ * and passed to the callback each time that it is called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+ virtual void setMatchCallback(URegexMatchCallback *callback,
+ const void *context,
+ UErrorCode &status);
+
+
+ /**
+ * Get the callback function for this URegularExpression.
+ *
+ * @param callback Out parameter, receives a pointer to the user-supplied
+ * callback function.
+ * @param context Out parameter, receives the user context pointer that
+ * was set when uregex_setMatchCallback() was called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+ virtual void getMatchCallback(URegexMatchCallback *&callback,
+ const void *&context,
+ UErrorCode &status);
+
+
+ /**
+ * Set a progress callback function for use with find operations on this Matcher.
+ * During find operations, the callback will be invoked after each return from a
+ * match attempt, giving the application the opportunity to terminate a long-running
+ * find operation.
+ *
+ * @param callback A pointer to the user-supplied callback function.
+ * @param context User context pointer. The value supplied at the
+ * time the callback function is set will be saved
+ * and passed to the callback each time that it is called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+ virtual void setFindProgressCallback(URegexFindProgressCallback *callback,
+ const void *context,
+ UErrorCode &status);
+
+
+ /**
+ * Get the find progress callback function for this URegularExpression.
+ *
+ * @param callback Out parameter, receives a pointer to the user-supplied
+ * callback function.
+ * @param context Out parameter, receives the user context pointer that
+ * was set when uregex_setFindProgressCallback() was called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+ virtual void getFindProgressCallback(URegexFindProgressCallback *&callback,
+ const void *&context,
+ 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);
+ void init(UErrorCode &status); // Common initialization
+ void init2(UText *t, UErrorCode &e); // Common initialization, part 2.
+
+ friend class RegexPattern;
+ friend class RegexCImpl;
+public:
+ /** @internal */
+ void resetPreserveRegion(); // Reset matcher state, but preserve any region.
+private:
+
+ //
+ // MatchAt This is the internal interface to the match engine itself.
+ // Match status comes back in matcher member variables.
+ //
+ void MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status);
+ inline void backTrack(int64_t &inputIdx, int32_t &patIdx);
+ UBool isWordBoundary(int64_t pos); // perform Perl-like \b test
+ UBool isUWordBoundary(int64_t pos); // perform RBBI based \b test
+ REStackFrame *resetStack();
+ inline REStackFrame *StateSave(REStackFrame *fp, int64_t savePatIdx, UErrorCode &status);
+ void IncrementTime(UErrorCode &status);
+ UBool ReportFindProgress(int64_t matchIndex, UErrorCode &status);
+
+ int64_t appendGroup(int32_t groupNum, UText *dest, UErrorCode &status) const;
+
+ UBool findUsingChunk();
+ void MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &status);
+ UBool isChunkWordBoundary(int32_t pos);
+
+ const RegexPattern *fPattern;
+ RegexPattern *fPatternOwned; // Non-NULL if this matcher owns the pattern, and
+ // should delete it when through.
+
+ const UnicodeString *fInput; // The string being matched. Only used for input()
+ UText *fInputText; // The text being matched. Is never NULL.
+ UText *fAltInputText; // A shallow copy of the text being matched.
+ // Only created if the pattern contains backreferences.
+ int64_t fInputLength; // Full length of the input text.
+ int32_t fFrameSize; // The size of a frame in the backtrack stack.
+
+ int64_t fRegionStart; // Start of the input region, default = 0.
+ int64_t fRegionLimit; // End of input region, default to input.length.
+
+ int64_t fAnchorStart; // Region bounds for anchoring operations (^ or $).
+ int64_t fAnchorLimit; // See useAnchoringBounds
+
+ int64_t fLookStart; // Region bounds for look-ahead/behind and
+ int64_t fLookLimit; // and other boundary tests. See
+ // useTransparentBounds
+
+ int64_t fActiveStart; // Currently active bounds for matching.
+ int64_t fActiveLimit; // Usually is the same as region, but
+ // is changed to fLookStart/Limit when
+ // entering look around regions.
+
+ UBool fTransparentBounds; // True if using transparent bounds.
+ UBool fAnchoringBounds; // True if using anchoring bounds.
+
+ UBool fMatch; // True if the last attempted match was successful.
+ int64_t fMatchStart; // Position of the start of the most recent match
+ int64_t fMatchEnd; // First position after the end of the most recent match
+ // Zero if no previous match, even when a region
+ // is active.
+ int64_t fLastMatchEnd; // First position after the end of the previous match,
+ // or -1 if there was no previous match.
+ int64_t fAppendPosition; // First position after the end of the previous
+ // appendReplacement(). As described by the
+ // JavaDoc for Java Matcher, where it is called
+ // "append position"
+ UBool fHitEnd; // True if the last match touched the end of input.
+ UBool fRequireEnd; // True if the last match required end-of-input
+ // (matched $ or Z)
+
+ UVector64 *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.
+
+ int64_t *fData; // Data area for use by the compiled pattern.
+ int64_t fSmallData[8]; // Use this for data if it's enough.
+
+ int32_t fTimeLimit; // Max time (in arbitrary steps) to let the
+ // match engine run. Zero for unlimited.
+
+ int32_t fTime; // Match time, accumulates while matching.
+ int32_t fTickCounter; // Low bits counter for time. Counts down StateSaves.
+ // Kept separately from fTime to keep as much
+ // code as possible out of the inline
+ // StateSave function.
+
+ int32_t fStackLimit; // Maximum memory size to use for the backtrack
+ // stack, in bytes. Zero for unlimited.
+
+ URegexMatchCallback *fCallbackFn; // Pointer to match progress callback funct.
+ // NULL if there is no callback.
+ const void *fCallbackContext; // User Context ptr for callback function.
+
+ URegexFindProgressCallback *fFindProgressCallbackFn; // Pointer to match progress callback funct.
+ // NULL if there is no callback.
+ const void *fFindProgressCallbackContext; // User Context ptr for callback function.
+
+
+ UBool fInputUniStrMaybeMutable; // Set when fInputText wraps a UnicodeString that may be mutable - compatibility.
+
+ UBool fTraceDebug; // Set true for debug tracing of match engine.
+
+ UErrorCode fDeferredStatus; // Save error state 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-4.8.1/i18n/unicode/search.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/search.h
new file mode 100644
index 00000000000..71bbf2dd529
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/search.h
@@ -0,0 +1,575 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2011 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 && !UCONFIG_NO_BREAK_ITERATION
+
+#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 equal or 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 <tt>USEARCH_DONE</tt>.
+ * @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
+ * <p>
+ * When <tt>USEARCH_OVERLAP</tt> option is off, the last index of the
+ * result match is always less than <tt>position</tt>.
+ * When <tt>USERARCH_OVERLAP</tt> is on, the result match may span across
+ * <tt>position</tt>.
+ *
+ * @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-4.8.1/i18n/unicode/selfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/selfmt.h
new file mode 100644
index 00000000000..635144bb9b3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/selfmt.h
@@ -0,0 +1,367 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Copyright (C) 2010 , Yahoo! Inc.
+ ********************************************************************
+ *
+ * File SELFMT.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 11/11/09 kirtig Finished first cut of implementation.
+ ********************************************************************/
+
+#ifndef SELFMT
+#define SELFMT
+
+#include "unicode/messagepattern.h"
+#include "unicode/numfmt.h"
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: SelectFormat object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+class MessageFormat;
+
+/**
+ * <p><code>SelectFormat</code> supports the creation of internationalized
+ * messages by selecting phrases based on keywords. The pattern specifies
+ * how to map keywords to phrases and provides a default phrase. The
+ * object provided to the format method is a string that's matched
+ * against the keywords. If there is a match, the corresponding phrase
+ * is selected; otherwise, the default phrase is used.</p>
+ *
+ * <h4>Using <code>SelectFormat</code> for Gender Agreement</h4>
+ *
+ * <p>Note: Typically, select formatting is done via <code>MessageFormat</code>
+ * with a <code>select</code> argument type,
+ * rather than using a stand-alone <code>SelectFormat</code>.</p>
+ *
+ * <p>The main use case for the select format is gender based inflection.
+ * When names or nouns are inserted into sentences, their gender can affect pronouns,
+ * verb forms, articles, and adjectives. Special care needs to be
+ * taken for the case where the gender cannot be determined.
+ * The impact varies between languages:</p>
+ * \htmlonly
+ * <ul>
+ * <li>English has three genders, and unknown gender is handled as a special
+ * case. Names use the gender of the named person (if known), nouns referring
+ * to people use natural gender, and inanimate objects are usually neutral.
+ * The gender only affects pronouns: "he", "she", "it", "they".
+ *
+ * <li>German differs from English in that the gender of nouns is rather
+ * arbitrary, even for nouns referring to people ("M&#x00E4;dchen", girl, is neutral).
+ * The gender affects pronouns ("er", "sie", "es"), articles ("der", "die",
+ * "das"), and adjective forms ("guter Mann", "gute Frau", "gutes M&#x00E4;dchen").
+ *
+ * <li>French has only two genders; as in German the gender of nouns
+ * is rather arbitrary - for sun and moon, the genders
+ * are the opposite of those in German. The gender affects
+ * pronouns ("il", "elle"), articles ("le", "la"),
+ * adjective forms ("bon", "bonne"), and sometimes
+ * verb forms ("all&#x00E9;", "all&#x00E9;e").
+ *
+ * <li>Polish distinguishes five genders (or noun classes),
+ * human masculine, animate non-human masculine, inanimate masculine,
+ * feminine, and neuter.
+ * </ul>
+ * \endhtmlonly
+ * <p>Some other languages have noun classes that are not related to gender,
+ * but similar in grammatical use.
+ * Some African languages have around 20 noun classes.</p>
+ *
+ * <p><b>Note:</b>For the gender of a <i>person</i> in a given sentence,
+ * we usually need to distinguish only between female, male and other/unknown.</p>
+ *
+ * <p>To enable localizers to create sentence patterns that take their
+ * language's gender dependencies into consideration, software has to provide
+ * information about the gender associated with a noun or name to
+ * <code>MessageFormat</code>.
+ * Two main cases can be distinguished:</p>
+ *
+ * <ul>
+ * <li>For people, natural gender information should be maintained for each person.
+ * Keywords like "male", "female", "mixed" (for groups of people)
+ * and "unknown" could be used.
+ *
+ * <li>For nouns, grammatical gender information should be maintained for
+ * each noun and per language, e.g., in resource bundles.
+ * The keywords "masculine", "feminine", and "neuter" are commonly used,
+ * but some languages may require other keywords.
+ * </ul>
+ *
+ * <p>The resulting keyword is provided to <code>MessageFormat</code> as a
+ * parameter separate from the name or noun it's associated with. For example,
+ * to generate a message such as "Jean went to Paris", three separate arguments
+ * would be provided: The name of the person as argument 0, the gender of
+ * the person as argument 1, and the name of the city as argument 2.
+ * The sentence pattern for English, where the gender of the person has
+ * no impact on this simple sentence, would not refer to argument 1 at all:</p>
+ *
+ * <pre>{0} went to {2}.</pre>
+ *
+ * <p><b>Note:</b> The entire sentence should be included (and partially repeated)
+ * inside each phrase. Otherwise translators would have to be trained on how to
+ * move bits of the sentence in and out of the select argument of a message.
+ * (The examples below do not follow this recommendation!)</p>
+ *
+ * <p>The sentence pattern for French, where the gender of the person affects
+ * the form of the participle, uses a select format based on argument 1:</p>
+ *
+ * \htmlonly<pre>{0} est {1, select, female {all&#x00E9;e} other {all&#x00E9;}} &#x00E0; {2}.</pre>\endhtmlonly
+ *
+ * <p>Patterns can be nested, so that it's possible to handle interactions of
+ * number and gender where necessary. For example, if the above sentence should
+ * allow for the names of several people to be inserted, the following sentence
+ * pattern can be used (with argument 0 the list of people's names,
+ * argument 1 the number of people, argument 2 their combined gender, and
+ * argument 3 the city name):</p>
+ *
+ * \htmlonly
+ * <pre>{0} {1, plural,
+ * one {est {2, select, female {all&#x00E9;e} other {all&#x00E9;}}}
+ * other {sont {2, select, female {all&#x00E9;es} other {all&#x00E9;s}}}
+ * }&#x00E0; {3}.</pre>
+ * \endhtmlonly
+ *
+ * <h4>Patterns and Their Interpretation</h4>
+ *
+ * <p>The <code>SelectFormat</code> pattern string defines the phrase output
+ * for each user-defined keyword.
+ * The pattern is a sequence of (keyword, message) pairs.
+ * A keyword is a "pattern identifier": [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+</p>
+ *
+ * <p>Each message is a MessageFormat pattern string enclosed in {curly braces}.</p>
+ *
+ * <p>You always have to define a phrase for the default keyword
+ * <code>other</code>; this phrase is returned when the keyword
+ * provided to
+ * the <code>format</code> method matches no other keyword.
+ * If a pattern does not provide a phrase for <code>other</code>, the method
+ * it's provided to returns the error <code>U_DEFAULT_KEYWORD_MISSING</code>.
+ * <br>
+ * Pattern_White_Space between keywords and messages is ignored.
+ * Pattern_White_Space within a message is preserved and output.</p>
+ *
+ * <p><pre>Example:
+ * \htmlonly
+ *
+ * UErrorCode status = U_ZERO_ERROR;
+ * MessageFormat *msgFmt = new MessageFormat(UnicodeString("{0} est {1, select, female {all&#x00E9;e} other {all&#x00E9;}} &#x00E0; Paris."), Locale("fr"), status);
+ * if (U_FAILURE(status)) {
+ * return;
+ * }
+ * FieldPosition ignore(FieldPosition::DONT_CARE);
+ * UnicodeString result;
+ *
+ * char* str1= "Kirti,female";
+ * Formattable args1[] = {"Kirti","female"};
+ * msgFmt->format(args1, 2, result, ignore, status);
+ * cout << "Input is " << str1 << " and result is: " << result << endl;
+ * delete msgFmt;
+ *
+ * \endhtmlonly
+ * </pre>
+ * </p>
+ *
+ * Produces the output:<br>
+ * \htmlonly
+ * <code>Kirti est all&#x00E9;e &#x00E0; Paris.</code>
+ * \endhtmlonly
+ *
+ * @stable ICU 4.4
+ */
+
+class U_I18N_API SelectFormat : public Format {
+public:
+
+ /**
+ * Creates a new <code>SelectFormat</code> for a given pattern string.
+ * @param pattern the pattern for this <code>SelectFormat</code>.
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.4
+ */
+ SelectFormat(const UnicodeString& pattern, UErrorCode& status);
+
+ /**
+ * copy constructor.
+ * @stable ICU 4.4
+ */
+ SelectFormat(const SelectFormat& other);
+
+ /**
+ * Destructor.
+ * @stable ICU 4.4
+ */
+ virtual ~SelectFormat();
+
+ /**
+ * Sets the pattern used by this select format.
+ * for the keyword rules.
+ * Patterns and their interpretation are specified in the class description.
+ *
+ * @param pattern the pattern for this select format
+ * errors are returned to status if the pattern is invalid.
+ * @param status output param set to success/failure code on exit, which
+ * must not indicate a failure before the function call.
+ * @stable ICU 4.4
+ */
+ void applyPattern(const UnicodeString& pattern, UErrorCode& status);
+
+
+ using Format::format;
+
+ /**
+ * Selects the phrase for the given keyword
+ *
+ * @param keyword The keyword that is used to select an alternative.
+ * @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, which
+ * must not indicate a failure before the function call.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ UnicodeString& format(const UnicodeString& keyword,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Assignment operator
+ *
+ * @param other the SelectFormat object to copy from.
+ * @stable ICU 4.4
+ */
+ SelectFormat& operator=(const SelectFormat& other);
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the SelectFormat object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @stable ICU 4.4
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the SelectFormat object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @stable ICU 4.4
+ */
+ virtual UBool operator!=(const Format& other) const;
+
+ /**
+ * Clones this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ * @stable ICU 4.4
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Format an object to produce a string.
+ * This method handles keyword strings.
+ * If the Formattable object is not a <code>UnicodeString</code>,
+ * then it returns a failing UErrorCode.
+ *
+ * @param obj A keyword string that is used to select an alternative.
+ * @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 4.4
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Returns the pattern from applyPattern() or constructor.
+ *
+ * @param appendTo output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return the UnicodeString with inserted pattern.
+ * @stable ICU 4.4
+ */
+ UnicodeString& toPattern(UnicodeString& appendTo);
+
+ /**
+ * This method is not yet supported by <code>SelectFormat</code>.
+ * <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.
+ * @stable ICU 4.4
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ * @stable ICU 4.4
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ * @stable ICU 4.4
+ */
+ virtual UClassID getDynamicClassID() const;
+
+private:
+ friend class MessageFormat;
+
+ SelectFormat(); // default constructor not implemented.
+
+ /**
+ * Finds the SelectFormat sub-message for the given keyword, or the "other" sub-message.
+ * @param pattern A MessagePattern.
+ * @param partIndex the index of the first SelectFormat argument style part.
+ * @param keyword a keyword to be matched to one of the SelectFormat argument's keywords.
+ * @param ec Error code.
+ * @return the sub-message start part index.
+ */
+ static int32_t findSubMessage(const MessagePattern& pattern, int32_t partIndex,
+ const UnicodeString& keyword, UErrorCode& ec);
+
+ MessagePattern msgPattern;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _SELFMT
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/simpletz.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/simpletz.h
new file mode 100644
index 00000000000..9e74fc51710
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/simpletz.h
@@ -0,0 +1,927 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2011, 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, if Daylight Savings
+ * Time starts or ends at the last Sunday a month, use <code>dayOfWeekInMonth = -1</code>
+ * along with <code>dayOfWeek = UCAL_SUNDAY</code> to specify the rule.
+ *
+ * @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 second Sunday in March, at 2 AM in standard time.
+ * Therefore, you can set the start rule by calling:
+ * setStartRule(UCAL_MARCH, 2, UCAL_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 second Sunday in March, at 2 AM in standard time.
+ * Therefore, you can set the start rule by calling:
+ * setStartRule(UCAL_MARCH, 2, UCAL_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, if 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(UCAL_OCTOBER, -1, UCAL_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, if 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(UCAL_OCTOBER, -1, UCAL_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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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 dstSavings 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-4.8.1/i18n/unicode/smpdtfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/smpdtfmt.h
new file mode 100644
index 00000000000..927729b4b1c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/smpdtfmt.h
@@ -0,0 +1,1238 @@
+/*
+* Copyright (C) 1997-2011, 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;
+class FieldPositionHandler;
+class TimeZoneFormat;
+
+/**
+ *
+ * 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
+ * Q Quarter (Text & Number) Q2 & 02
+ * 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) (Text & Number) Tues & 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
+ * V time zone (abreviation) (Text) PT
+ * VVVV time zone (location) (Text) United States (Los Angeles)
+ * g Julian day (Number) 2451334
+ * A milliseconds in day (Number) 69540000
+ * q stand alone quarter (Text & Number) Q2 & 02
+ * L stand alone month (Text & Number) July & 07
+ * c stand alone day of week (Text & Number) Tuesday & 2
+ * ' 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, numbering system override, 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>
+ * A numbering system override is a string containing either the name of a known numbering system,
+ * or a set of field and numbering system pairs that specify which fields are to be formattied with
+ * the alternate numbering system. For example, to specify that all numeric fields in the specified
+ * date or time pattern are to be rendered using Thai digits, simply specify the numbering system override
+ * as "thai". To specify that just the year portion of the date be formatted using Hebrew numbering,
+ * use the override string "y=hebrew". Numbering system overrides can be combined using a semi-colon
+ * character in the override string, such as "d=decimal;M=arabic;y=hebrew", etc.
+ *
+ * <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 override the override string.
+ * @param status Output param set to success/failure code.
+ * @stable ICU 4.2
+ */
+ SimpleDateFormat(const UnicodeString& pattern,
+ const UnicodeString& override,
+ 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, numbering system override, 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>
+ * A numbering system override is a string containing either the name of a known numbering system,
+ * or a set of field and numbering system pairs that specify which fields are to be formattied with
+ * the alternate numbering system. For example, to specify that all numeric fields in the specified
+ * date or time pattern are to be rendered using Thai digits, simply specify the numbering system override
+ * as "thai". To specify that just the year portion of the date be formatted using Hebrew numbering,
+ * use the override string "y=hebrew". Numbering system overrides can be combined using a semi-colon
+ * character in the override string, such as "d=decimal;M=arabic;y=hebrew", etc.
+ * <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 override the numbering system override.
+ * @param locale the given locale.
+ * @param status Output param set to success/failure code.
+ * @stable ICU 4.2
+ */
+ SimpleDateFormat(const UnicodeString& pattern,
+ const UnicodeString& override,
+ 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;
+
+
+ using DateFormat::format;
+
+ /**
+ * 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 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Field values
+ * are defined in UDateFormatField.
+ * @param status Input/output param set to success/failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& format( Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) 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 Input/output param set to success/failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format( const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) 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 posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Field values
+ * are defined in UDateFormatField.
+ * @param status Input/output param set to success/failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ virtual UnicodeString& format( const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ 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 date the Date value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param posIter On return, can be used to iterate over positions
+ * of fields generated by this format call. Field values
+ * are defined in UDateFormatField.
+ * @param status Input/output param set to success/failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.4
+ */
+ UnicodeString& format(UDate date,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) 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);
+
+ /**
+ * This is for ICU internal use only. Please do not use.
+ * Check whether the 'field' is smaller than all the fields covered in
+ * pattern, return TRUE if it is. The sequence of calendar field,
+ * from large to small is: ERA, YEAR, MONTH, DATE, AM_PM, HOUR, MINUTE,...
+ * @param field the calendar field need to check against
+ * @return TRUE if the 'field' is smaller than all the fields
+ * covered in pattern. FALSE otherwise.
+ * @internal ICU 4.0
+ */
+ UBool isFieldUnitIgnored(UCalendarDateFields field) const;
+
+
+ /**
+ * This is for ICU internal use only. Please do not use.
+ * Check whether the 'field' is smaller than all the fields covered in
+ * pattern, return TRUE if it is. The sequence of calendar field,
+ * from large to small is: ERA, YEAR, MONTH, DATE, AM_PM, HOUR, MINUTE,...
+ * @param pattern the pattern to check against
+ * @param field the calendar field need to check against
+ * @return TRUE if the 'field' is smaller than all the fields
+ * covered in pattern. FALSE otherwise.
+ * @internal ICU 4.0
+ */
+ static UBool isFieldUnitIgnored(const UnicodeString& pattern,
+ UCalendarDateFields field);
+
+
+
+ /**
+ * This is for ICU internal use only. Please do not use.
+ * Get the locale of this simple date formatter.
+ * It is used in DateIntervalFormat.
+ *
+ * @return locale in this simple date formatter
+ * @internal ICU 4.0
+ */
+ const Locale& getSmpFmtLocale(void) const;
+
+
+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
+
+ /**
+ * Hook called by format(... FieldPosition& ...) and format(...FieldPositionIterator&...)
+ */
+ UnicodeString& _format(Calendar& cal, UnicodeString& appendTo, FieldPositionHandler& handler,
+ UErrorCode& status) const;
+
+ /**
+ * 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 handler Records information about field positions.
+ * @param cal Calendar to use
+ * @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,
+ FieldPositionHandler& handler,
+ 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 currentNumberFormat
+ * @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(NumberFormat *currentNumberFormat,
+ 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 status 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 function used by subParse to match literal pattern text.
+ *
+ * @param pattern the pattern string
+ * @param patternOffset the starting offset into the pattern text. On
+ * outupt will be set the offset of the first non-literal character in the pattern
+ * @param text the text being parsed
+ * @param textOffset the starting offset into the text. On output
+ * will be set to the offset of the character after the match
+ * @param lenient <code>TRUE</code> if the parse is lenient, <code>FALSE</code> otherwise.
+ *
+ * @return <code>TRUE</code> if the literal text could be matched, <code>FALSE</code> otherwise.
+ */
+ static UBool matchLiterals(const UnicodeString &pattern, int32_t &patternOffset,
+ const UnicodeString &text, int32_t &textOffset, UBool lenient);
+
+ /**
+ * 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 allowNegative
+ * @param ambiguousYear If true then the two-digit year == the default start year.
+ * @param saveHebrewMonth Used to hang onto month until year is known.
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param patLoc
+ * @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[], int32_t& saveHebrewMonth, Calendar& cal,
+ int32_t patLoc) const;
+
+ void parseInt(const UnicodeString& text,
+ Formattable& number,
+ ParsePosition& pos,
+ UBool allowNegative,
+ NumberFormat *fmt) const;
+
+ void parseInt(const UnicodeString& text,
+ Formattable& number,
+ int32_t maxDigits,
+ ParsePosition& pos,
+ UBool allowNegative,
+ NumberFormat *fmt) const;
+
+ int32_t checkIntSuffix(const UnicodeString& text, int32_t start,
+ int32_t patLoc, UBool isNegative) 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);
+
+ /**
+ * 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.
+ * @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 compareSimpleAffix(const UnicodeString& affix,
+ const UnicodeString& input,
+ int32_t pos) const;
+
+ /**
+ * Skip over a run of zero or more Pattern_White_Space characters at
+ * pos in text.
+ */
+ int32_t skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const;
+
+ /**
+ * Skip over a run of zero or more isUWhiteSpace() characters at pos
+ * in text.
+ */
+ int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos) const;
+
+ /**
+ * Private methods for formatting/parsing GMT string
+ */
+ void appendGMT(NumberFormat *currentNumberFormat,UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const;
+ void formatGMTDefault(NumberFormat *currentNumberFormat,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);
+
+ /**
+ * Initialize NumberFormat instances used for numbering system overrides.
+ */
+ void initNumberFormatters(const Locale &locale,UErrorCode &status);
+
+ /**
+ * Get the numbering system to be used for a particular field.
+ */
+ NumberFormat * getNumberFormatByIndex(UDateFormatField index) const;
+
+ /**
+ * Parse the given override string and set up structures for number formats
+ */
+ void processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, 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[];
+
+ /**
+ * Lazy TimeZoneFormat instantiation, semantically const
+ */
+ TimeZoneFormat *tzFormat() const;
+
+ /**
+ * Used to map Calendar field to field level.
+ * The larger the level, the smaller the field unit.
+ * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10,
+ * UCAL_MONTH level is 20.
+ */
+ static const int32_t fgCalendarFieldToLevel[];
+ static const int32_t fgPatternCharToLevel[];
+
+ /**
+ * The formatting pattern for this formatter.
+ */
+ UnicodeString fPattern;
+
+ /**
+ * The numbering system override for dates.
+ */
+ UnicodeString fDateOverride;
+
+ /**
+ * The numbering system override for times.
+ */
+ UnicodeString fTimeOverride;
+
+
+ /**
+ * 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
+
+ /**
+ * The time zone formatter
+ */
+ TimeZoneFormat* fTimeZoneFormat;
+
+ /**
+ * 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
+
+ typedef struct NSOverride {
+ NumberFormat *nf;
+ int32_t hash;
+ NSOverride *next;
+ } NSOverride;
+
+ /*
+ * MessageFormat instances used for localized GMT format
+ */
+ enum {
+ kGMTNegativeHMS = 0,
+ kGMTNegativeHM,
+ kGMTPositiveHMS,
+ kGMTPositiveHM,
+
+ kNumGMTFormatters
+ };
+ enum {
+ kGMTNegativeHMSMinLenIdx = 0,
+ kGMTPositiveHMSMinLenIdx,
+
+ kNumGMTFormatMinLengths
+ };
+
+ MessageFormat **fGMTFormatters;
+ // If a GMT hour format has a second field, we need to make sure
+ // the length of input localized GMT string must match the expected
+ // length. Otherwise, sub DateForamt handling offset format may
+ // unexpectedly success parsing input GMT string without second field.
+ // See #6880 about this issue.
+ // TODO: SimpleDateFormat should provide an option to invalidate
+ //
+ int32_t fGMTFormatHmsMinLen[kNumGMTFormatMinLengths];
+
+ NumberFormat **fNumberFormatters;
+
+ NSOverride *fOverrideList;
+
+ 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(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return DateFormat::format(obj, appendTo, pos, status);
+}
+
+inline UnicodeString&
+SimpleDateFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const
+{
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return DateFormat::format(obj, appendTo, posIter, 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,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return DateFormat::format(date, appendTo, posIter, status);
+}
+
+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-4.8.1/i18n/unicode/sortkey.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/sortkey.h
new file mode 100644
index 00000000000..61c9408a612
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/sortkey.h
@@ -0,0 +1,329 @@
+/*
+ *****************************************************************************
+ * Copyright (C) 1996-2011, 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 capacity Size of the values array.
+ * @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 capacity, int32_t count);
+ /**
+ * Set a new length for a new sort key in the existing fBytes.
+ */
+ void setLength(int32_t newLength);
+
+ /*
+ * 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-4.8.1/i18n/unicode/stsearch.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/stsearch.h
new file mode 100644
index 00000000000..8499752e6d0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/stsearch.h
@@ -0,0 +1,518 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2008 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 && !UCONFIG_NO_BREAK_ITERATION
+
+#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-4.8.1/i18n/unicode/tblcoll.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tblcoll.h
new file mode 100644
index 00000000000..52f37ddc588
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tblcoll.h
@@ -0,0 +1,993 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C++ API: RuleBasedCollator class provides the simple implementation of Collator.
+ */
+
+/**
+* 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"
+
+
+#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;
+
+ /**
+ * Compares two strings using the Collator.
+ * Returns whether the first one compares less than/equal to/greater than
+ * the second one.
+ * This version takes UCharIterator input.
+ * @param sIter the first ("source") string iterator
+ * @param tIter the second ("target") string iterator
+ * @param status ICU status
+ * @return UCOL_LESS, UCOL_EQUAL or UCOL_GREATER
+ * @stable ICU 4.2
+ */
+ virtual UCollationResult compare(UCharIterator &sIter,
+ UCharIterator &tIter,
+ 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);
+
+ /**
+ * Retrieves the reordering codes for this collator.
+ * @param dest The array to fill with the script ordering.
+ * @param destCapacity The length of dest. If it is 0, then dest may be NULL and the function
+ * will only return the length of the result without writing any of the result string (pre-flighting).
+ * @param status A reference to an error code value, which must not indicate
+ * a failure before the function call.
+ * @return The length of the script ordering array.
+ * @see ucol_setReorderCodes
+ * @see Collator#getEquivalentReorderCodes
+ * @see Collator#setReorderCodes
+ * @draft ICU 4.8
+ */
+ virtual int32_t U_EXPORT2 getReorderCodes(int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode& status) const;
+
+ /**
+ * Sets the ordering of scripts for this collator.
+ * @param reorderCodes An array of script codes in the new order. This can be NULL if the
+ * length is also set to 0. An empty array will clear any reordering codes on the collator.
+ * @param reorderCodesLength The length of reorderCodes.
+ * @param status error code
+ * @see Collator#getReorderCodes
+ * @see Collator#getEquivalentReorderCodes
+ * @draft ICU 4.8
+ */
+ virtual void U_EXPORT2 setReorderCodes(const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode& status) ;
+
+ /**
+ * Retrieves the reorder codes that are grouped with the given reorder code. Some reorder
+ * codes will be grouped and must reorder together.
+ * @param reorderCode The reorder code to determine equivalence for.
+ * @param dest The array to fill with the script equivalene reordering codes.
+ * @param destCapacity The length of dest. If it is 0, then dest may be NULL and the
+ * function will only return the length of the result without writing any of the result
+ * string (pre-flighting).
+ * @param status A reference to an error code value, which must not indicate
+ * a failure before the function call.
+ * @return The length of the of the reordering code equivalence array.
+ * @see ucol_setReorderCodes
+ * @see Collator#getReorderCodes
+ * @see Collator#setReorderCodes
+ * @draft ICU 4.8
+ */
+ static int32_t U_EXPORT2 getEquivalentReorderCodes(int32_t reorderCode,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode& status);
+
+
+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
+ */
+ 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
+ * @param actualLocale the actual locale
+ * @internal
+ */
+ virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale, const Locale& actualLocale);
+
+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-4.8.1/i18n/unicode/timezone.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/timezone.h
new file mode 100644
index 00000000000..fa5ea72810a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/timezone.h
@@ -0,0 +1,853 @@
+/*************************************************************************
+* Copyright (c) 1997-2011, 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"
+#include "unicode/ucal.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 US Pacific
+ * Time zone is "America/Los_Angeles". So, you can get a Pacific Time <code>TimeZone</code> object
+ * with:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * TimeZone *tz = TimeZone::createTimeZone("America/Los_Angeles");
+ * </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, US Pacific
+ * 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/Los_Angeles").
+ * 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>, 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 system time zone IDs with the given
+ * filter conditions.
+ * @param zoneType The system time zone type.
+ * @param region The ISO 3166 two-letter country code or UN M.49
+ * three-digit area code. When NULL, no filtering
+ * done by region.
+ * @param rawOffset An offset from GMT in milliseconds, ignoring
+ * the effect of daylight savings time, if any.
+ * When NULL, no filtering done by zone offset.
+ * @param ec Output param to filled in with a success or
+ * an error.
+ * @return an enumeration object, owned by the caller.
+ * @draft ICU 4.8
+ */
+ static StringEnumeration* U_EXPORT2 createTimeZoneIDEnumeration(
+ USystemTimeZoneType zoneType,
+ const char* region,
+ const int32_t* rawOffset,
+ UErrorCode& ec);
+
+ /**
+ * 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);
+
+ /**
+ * 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"
+ * @stable ICU 3.8
+ */
+ static const char* U_EXPORT2 getTZDataVersion(UErrorCode& status);
+
+ /**
+ * Returns the canonical system timezone ID or the normalized
+ * custom time zone ID for the given time zone ID.
+ * @param id The input time zone ID to be canonicalized.
+ * @param canonicalID Receives the canonical system time zone ID
+ * or the custom time zone ID in normalized format.
+ * @param status Recevies the status. When the given time zone ID
+ * is neither a known system time zone ID nor a
+ * valid custom time zone ID, U_ILLEGAL_ARGUMENT_ERROR
+ * is set.
+ * @return A reference to the result.
+ * @stable ICU 4.0
+ */
+ static UnicodeString& U_EXPORT2 getCanonicalID(const UnicodeString& id,
+ UnicodeString& canonicalID, UErrorCode& status);
+
+ /**
+ * Returns the canonical system time zone ID or the normalized
+ * custom time zone ID for the given time zone ID.
+ * @param id The input time zone ID to be canonicalized.
+ * @param canonicalID Receives the canonical system time zone ID
+ * or the custom time zone ID in normalized format.
+ * @param isSystemID Receives if the given ID is a known system
+ * time zone ID.
+ * @param status Recevies the status. When the given time zone ID
+ * is neither a known system time zone ID nor a
+ * valid custom time zone ID, U_ILLEGAL_ARGUMENT_ERROR
+ * is set.
+ * @return A reference to the result.
+ * @stable ICU 4.0
+ */
+ static UnicodeString& U_EXPORT2 getCanonicalID(const UnicodeString& id,
+ UnicodeString& canonicalID, UBool& isSystemID, 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 time zone 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,
+ /**
+ * Selector for short generic display name
+ * @stable ICU 4.4
+ */
+ SHORT_GENERIC,
+ /**
+ * Selector for long generic display name
+ * @stable ICU 4.4
+ */
+ LONG_GENERIC,
+ /**
+ * Selector for short display name derived
+ * from time zone offset
+ * @stable ICU 4.4
+ */
+ SHORT_GMT,
+ /**
+ * Selector for long display name derived
+ * from time zone offset
+ * @stable ICU 4.4
+ */
+ LONG_GMT,
+ /**
+ * Selector for short display name derived
+ * from the time zone's fallback name
+ * @stable ICU 4.4
+ */
+ SHORT_COMMONLY_USED,
+ /**
+ * Selector for long display name derived
+ * from the time zone's fallback name
+ * @stable ICU 4.4
+ */
+ GENERIC_LOCATION
+ };
+
+ /**
+ * 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
+ * @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
+ * @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.
+ * <p><strong>Note:</strong>The default implementation of
+ * ICU TimeZone uses the tz database, which supports historic
+ * rule changes, for system time zones. With the implementation,
+ * there are time zones that used daylight savings time in the
+ * past, but no longer used currently. For example, Asia/Tokyo has
+ * never used daylight savings time since 1951. Most clients would
+ * expect that this method to return <code>FALSE</code> for such case.
+ * The default implementation of this method returns <code>TRUE</code>
+ * when the time zone uses daylight savings time in the current
+ * (Gregorian) calendar year.
+ * @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;
+
+ /**
+ * Gets the region code associated with the given
+ * system time zone ID. The region code is either ISO 3166
+ * 2-letter country code or UN M.49 3-digit area code.
+ * When the time zone is not associated with a specific location,
+ * for example - "Etc/UTC", "EST5EDT", then this method returns
+ * "001" (UN M.49 area code for World).
+ *
+ * @param id The system time zone ID.
+ * @param region Output buffer for receiving the region code.
+ * @param capacity The size of the output buffer.
+ * @param status Receives the status. When the given time zone ID
+ * is not a known system time zone ID,
+ * U_ILLEGAL_ARGUMENT_ERROR is set.
+ * @return The length of the output region code.
+ * @draft ICU 4.8
+ */
+ static int32_t U_EXPORT2 getRegion(const UnicodeString& id,
+ char *region, int32_t capacity, UErrorCode& status);
+
+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;
+
+
+ static TimeZone* createCustomTimeZone(const UnicodeString&); // Creates a time zone based on the string.
+
+ /**
+ * Finds the given ID in the Olson tzdata. If the given ID is found in the tzdata,
+ * returns the pointer to the ID resource. This method is exposed through ZoneMeta class
+ * for ICU internal implementation and useful for building hashtable using a time zone
+ * ID as a key.
+ * @param id zone id string
+ * @return the pointer of the ID resource, or NULL.
+ */
+ static const UChar* findID(const UnicodeString& id);
+
+ /**
+ * Resolve a link in Olson tzdata. When the given id is known and it's not a link,
+ * the id itself is returned. When the given id is known and it is a link, then
+ * dereferenced zone id is returned. When the given id is unknown, then it returns
+ * NULL.
+ * @param id zone id string
+ * @return the dereferenced zone or NULL
+ */
+ static const UChar* dereferOlsonLink(const UnicodeString& id);
+
+ /**
+ * Returns the region code associated with the given zone,
+ * or NULL if the zone is not known.
+ * @param id zone id string
+ * @return the region associated with the given zone
+ */
+ static const UChar* getRegion(const UnicodeString& id);
+
+ /**
+ * Returns the region code associated with the given zone,
+ * or NULL if the zone is not known.
+ * @param id zone id string
+ * @param status Status parameter
+ * @return the region associated with the given zone
+ */
+ static const UChar* getRegion(const UnicodeString& id, UErrorCode& status);
+
+ /**
+ * Parses the given custom time zone identifier
+ * @param id id A string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
+ * GMT[+-]hh.
+ * @param sign Receves parsed sign, 1 for positive, -1 for negative.
+ * @param hour Receives parsed hour field
+ * @param minute Receives parsed minute field
+ * @param second Receives parsed second field
+ * @return Returns TRUE when the given custom id is valid.
+ */
+ static UBool parseCustomID(const UnicodeString& id, int32_t& sign, int32_t& hour,
+ int32_t& minute, int32_t& second);
+
+ /**
+ * Parse a custom time zone identifier and return the normalized
+ * custom time zone identifier for the given custom id string.
+ * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
+ * GMT[+-]hh.
+ * @param normalized Receives the normalized custom ID
+ * @param status Receives the status. When the input ID string is invalid,
+ * U_ILLEGAL_ARGUMENT_ERROR is set.
+ * @return The normalized custom id string.
+ */
+ static UnicodeString& getCustomID(const UnicodeString& id, UnicodeString& normalized,
+ UErrorCode& status);
+
+ /**
+ * Returns the normalized custome time zone ID for the given offset fields.
+ * @param hour offset hours
+ * @param min offset minutes
+ * @param sec offset seconds
+ * @param negative sign of the offset, TRUE for negative offset.
+ * @param id Receves the format result (normalized custom ID)
+ * @return The reference to id
+ */
+ static UnicodeString& formatCustomID(int32_t hour, int32_t min, int32_t sec,
+ UBool negative, UnicodeString& id);
+
+ /**
+ * 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);
+ static TimeZone* createSystemTimeZone(const UnicodeString& name, UErrorCode& ec);
+
+ UnicodeString fID; // this time zone's ID
+
+ friend class TZEnumeration;
+};
+
+
+// -------------------------------------
+
+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-4.8.1/i18n/unicode/tmunit.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmunit.h
new file mode 100644
index 00000000000..6eda105c12f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmunit.h
@@ -0,0 +1,149 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TMUNIT_H__
+#define __TMUNIT_H__
+
+
+/**
+ * \file
+ * \brief C++ API: time unit object
+ */
+
+
+#include "unicode/measunit.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Measurement unit for time units.
+ * @see TimeUnitAmount
+ * @see TimeUnit
+ * @stable ICU 4.2
+ */
+class U_I18N_API TimeUnit: public MeasureUnit {
+public:
+ /**
+ * Constants for all the time units we supported.
+ * @stable ICU 4.2
+ */
+ enum UTimeUnitFields {
+ UTIMEUNIT_YEAR,
+ UTIMEUNIT_MONTH,
+ UTIMEUNIT_DAY,
+ UTIMEUNIT_WEEK,
+ UTIMEUNIT_HOUR,
+ UTIMEUNIT_MINUTE,
+ UTIMEUNIT_SECOND,
+ UTIMEUNIT_FIELD_COUNT
+ };
+
+ /**
+ * Create Instance.
+ * @param timeUnitField time unit field based on which the instance
+ * is created.
+ * @param status input-output error code.
+ * If the timeUnitField is invalid,
+ * then this will be set to U_ILLEGAL_ARGUMENT_ERROR.
+ * @return a TimeUnit instance
+ * @stable ICU 4.2
+ */
+ static TimeUnit* U_EXPORT2 createInstance(UTimeUnitFields timeUnitField,
+ UErrorCode& status);
+
+
+ /**
+ * Override clone.
+ * @stable ICU 4.2
+ */
+ virtual UObject* clone() const;
+
+ /**
+ * Copy operator.
+ * @stable ICU 4.2
+ */
+ TimeUnit(const TimeUnit& other);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 4.2
+ */
+ TimeUnit& operator=(const TimeUnit& other);
+
+ /**
+ * Equality operator.
+ * @return true if 2 objects are the same.
+ * @stable ICU 4.2
+ */
+ virtual UBool operator==(const UObject& other) const;
+
+ /**
+ * Non-Equality operator.
+ * @return true if 2 objects are not the same.
+ * @stable ICU 4.2
+ */
+ 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 4.2
+ */
+ 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 4.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+
+ /**
+ * Get time unit field.
+ * @return time unit field.
+ * @stable ICU 4.2
+ */
+ UTimeUnitFields getTimeUnitField() const;
+
+ /**
+ * Destructor.
+ * @stable ICU 4.2
+ */
+ virtual ~TimeUnit();
+
+private:
+ UTimeUnitFields fTimeUnitField;
+
+ /**
+ * Constructor
+ * @internal ICU 4.2
+ */
+ TimeUnit(UTimeUnitFields timeUnitField);
+
+};
+
+
+inline UBool
+TimeUnit::operator!=(const UObject& other) const {
+ return !operator==(other);
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TMUNIT_H__
+//eof
+//
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutamt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutamt.h
new file mode 100644
index 00000000000..bd2b8a4a9e2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutamt.h
@@ -0,0 +1,168 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TMUTAMT_H__
+#define __TMUTAMT_H__
+
+
+/**
+ * \file
+ * \brief C++ API: time unit amount object.
+ */
+
+#include "unicode/measure.h"
+#include "unicode/tmunit.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * Express a duration as a time unit and number. Patterned after Currency.
+ * @see TimeUnitAmount
+ * @see TimeUnitFormat
+ * @stable ICU 4.2
+ */
+class U_I18N_API TimeUnitAmount: public Measure {
+public:
+ /**
+ * Construct TimeUnitAmount object with the given number and the
+ * given time unit.
+ * @param number a numeric object; number.isNumeric() must be TRUE
+ * @param timeUnitField the time unit field of a time unit
+ * @param status the input-output error code.
+ * If the number is not numeric or the timeUnitField
+ * is not valid,
+ * then this will be set to a failing value:
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ * @stable ICU 4.2
+ */
+ TimeUnitAmount(const Formattable& number,
+ TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status);
+
+ /**
+ * Construct TimeUnitAmount object with the given numeric amount and the
+ * given time unit.
+ * @param amount a numeric amount.
+ * @param timeUnitField the time unit field on which a time unit amount
+ * object will be created.
+ * @param status the input-output error code.
+ * If the timeUnitField is not valid,
+ * then this will be set to a failing value:
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ * @stable ICU 4.2
+ */
+ TimeUnitAmount(double amount, TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status);
+
+
+ /**
+ * Copy constructor
+ * @stable ICU 4.2
+ */
+ TimeUnitAmount(const TimeUnitAmount& other);
+
+
+ /**
+ * Assignment operator
+ * @stable ICU 4.2
+ */
+ TimeUnitAmount& operator=(const TimeUnitAmount& other);
+
+
+ /**
+ * Clone.
+ * @return a polymorphic clone of this object. The result will have the same class as returned by getDynamicClassID().
+ * @stable ICU 4.2
+ */
+ virtual UObject* clone() const;
+
+
+ /**
+ * Destructor
+ * @stable ICU 4.2
+ */
+ virtual ~TimeUnitAmount();
+
+
+ /**
+ * Equality operator.
+ * @param other the object to compare to.
+ * @return true if this object is equal to the given object.
+ * @stable ICU 4.2
+ */
+ virtual UBool operator==(const UObject& other) const;
+
+
+ /**
+ * Not-equality operator.
+ * @param other the object to compare to.
+ * @return true if this object is not equal to the given object.
+ * @stable ICU 4.2
+ */
+ UBool operator!=(const UObject& other) 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() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 4.2
+ */
+ 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 4.2
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+
+ /**
+ * Get the time unit.
+ * @return time unit object.
+ * @stable ICU 4.2
+ */
+ const TimeUnit& getTimeUnit() const;
+
+ /**
+ * Get the time unit field value.
+ * @return time unit field value.
+ * @stable ICU 4.2
+ */
+ TimeUnit::UTimeUnitFields getTimeUnitField() const;
+};
+
+
+
+inline UBool
+TimeUnitAmount::operator!=(const UObject& other) const {
+ return !operator==(other);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TMUTAMT_H__
+//eof
+//
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutfmt.h
new file mode 100644
index 00000000000..8252cc205b8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tmutfmt.h
@@ -0,0 +1,270 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2011, Google, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#ifndef __TMUTFMT_H__
+#define __TMUTFMT_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse duration in single time unit
+ */
+
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/tmunit.h"
+#include "unicode/tmutamt.h"
+#include "unicode/measfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/plurrule.h"
+
+/**
+ * Constants for various styles.
+ * There are 2 styles: full name and abbreviated name.
+ * For example, for English, the full name for hour duration is "3 hours",
+ * and the abbreviated name is "3 hrs".
+ * @draft ICU 4.8
+ */
+enum UTimeUnitFormatStyle {
+ /** @draft ICU 4.8 */
+ UTMUTFMT_FULL_STYLE,
+ /** @draft ICU 4.8 */
+ UTMUTFMT_ABBREVIATED_STYLE,
+ /** @draft ICU 4.8 */
+ UTMUTFMT_FORMAT_STYLE_COUNT
+};
+typedef enum UTimeUnitFormatStyle UTimeUnitFormatStyle; /**< @draft ICU 4.8 */
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+
+
+/**
+ * Format or parse a TimeUnitAmount, using plural rules for the units where available.
+ *
+ * <P>
+ * Code Sample:
+ * <pre>
+ * // create time unit amount instance - a combination of Number and time unit
+ * UErrorCode status = U_ZERO_ERROR;
+ * TimeUnitAmount* source = new TimeUnitAmount(2, TimeUnit::UTIMEUNIT_YEAR, status);
+ * // create time unit format instance
+ * TimeUnitFormat* format = new TimeUnitFormat(Locale("en"), status);
+ * // format a time unit amount
+ * UnicodeString formatted;
+ * Formattable formattable;
+ * if (U_SUCCESS(status)) {
+ * formattable.adoptObject(source);
+ * formatted = ((Format*)format)->format(formattable, formatted, status);
+ * Formattable result;
+ * ((Format*)format)->parseObject(formatted, result, status);
+ * if (U_SUCCESS(status)) {
+ * assert (result == formattable);
+ * }
+ * }
+ * </pre>
+ *
+ * <P>
+ * @see TimeUnitAmount
+ * @see TimeUnitFormat
+ * @draft ICU 4.2
+ */
+class U_I18N_API TimeUnitFormat: public MeasureFormat {
+public:
+
+ /**
+ * Create TimeUnitFormat with default locale, and full name style.
+ * Use setLocale and/or setFormat to modify.
+ * @stable ICU 4.2
+ */
+ TimeUnitFormat(UErrorCode& status);
+
+ /**
+ * Create TimeUnitFormat given locale, and full name style.
+ * @stable ICU 4.2
+ */
+ TimeUnitFormat(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Create TimeUnitFormat given locale and style.
+ * @draft ICU 4.8
+ */
+ TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.2
+ */
+ TimeUnitFormat(const TimeUnitFormat&);
+
+ /**
+ * deconstructor
+ * @stable ICU 4.2
+ */
+ virtual ~TimeUnitFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @stable ICU 4.2
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Assignment operator
+ * @stable ICU 4.2
+ */
+ TimeUnitFormat& operator=(const TimeUnitFormat& other);
+
+
+ /**
+ * 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 4.2
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Return true if the given Format objects are not 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 not semantically equal.
+ * @stable ICU 4.2
+ */
+ UBool operator!=(const Format& other) const;
+
+ /**
+ * Set the locale used for formatting or parsing.
+ * @param locale the locale to be set
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ void setLocale(const Locale& locale, UErrorCode& status);
+
+
+ /**
+ * Set the number format used for formatting or parsing.
+ * @param format the number formatter to be set
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.2
+ */
+ void setNumberFormat(const NumberFormat& format, UErrorCode& status);
+
+
+ using MeasureFormat::format;
+
+ /**
+ * Format a TimeUnitAmount.
+ * If the formattable object is not a time unit amount object,
+ * or the number in time unit amount is not a double type or long type
+ * numeric, it returns a failing status: U_ILLEGAL_ARGUMENT_ERROR.
+ * @see Format#format(const Formattable&, UnicodeString&, FieldPosition&, UErrorCode&) const
+ * @stable ICU 4.2
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Parse a TimeUnitAmount.
+ * @see Format#parseObject(const UnicodeString&, Formattable&, ParsePosition&) const;
+ * @stable ICU 4.2
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) 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() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 4.2
+ */
+ 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 4.2
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ NumberFormat* fNumberFormat;
+ Locale fLocale;
+ Hashtable* fTimeUnitToCountToPatterns[TimeUnit::UTIMEUNIT_FIELD_COUNT];
+ PluralRules* fPluralRules;
+ UTimeUnitFormatStyle fStyle;
+
+ void create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status);
+
+ // it might actually be simpler to make them Decimal Formats later.
+ // initialize all private data members
+ void setup(UErrorCode& status);
+
+ // initialize data member without fill in data for fTimeUnitToCountToPattern
+ void initDataMembers(UErrorCode& status);
+
+ // initialize fTimeUnitToCountToPatterns from current locale's resource.
+ void readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, UErrorCode& status);
+
+ // check completeness of fTimeUnitToCountToPatterns against all time units,
+ // and all plural rules, fill in fallback as necessary.
+ void checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& status);
+
+ // fill in fTimeUnitToCountToPatterns from locale fall-back chain
+ void searchInLocaleChain(UTimeUnitFormatStyle style, const char* key, const char* localeName,
+ TimeUnit::UTimeUnitFields field, const UnicodeString&,
+ const char*, Hashtable*, UErrorCode&);
+
+ // initialize hash table
+ Hashtable* initHash(UErrorCode& status);
+
+ // delete hash table
+ void deleteHash(Hashtable* htable);
+
+ // copy hash table
+ void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
+ // get time unit name, such as "year", from time unit field enum, such as
+ // UTIMEUNIT_YEAR.
+ static const char* getTimeUnitName(TimeUnit::UTimeUnitFields field, UErrorCode& status);
+};
+
+
+
+inline UBool
+TimeUnitFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TMUTFMT_H__
+//eof
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/translit.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/translit.h
new file mode 100644
index 00000000000..df56db3d449
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/translit.h
@@ -0,0 +1,1320 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2011, 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.) This 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.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param index an array of three integers.
+ * @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(UErrorCode &status);
+
+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-4.8.1/i18n/unicode/tzrule.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tzrule.h
new file mode 100644
index 00000000000..afa40148d42
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tzrule.h
@@ -0,0 +1,828 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, 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.
+ *
+ * @stable ICU 3.8
+ */
+class U_I18N_API TimeZoneRule : public UObject {
+public:
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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"
+ * @stable ICU 3.8
+ */
+ UnicodeString& getName(UnicodeString& name) const;
+
+ /**
+ * Gets the standard time offset.
+ * @return The standard time offset from UTC in milliseconds.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings);
+
+ /**
+ * Copy constructor.
+ * @param source The TimeZoneRule object to be copied.
+ * @stable ICU 3.8
+ */
+ TimeZoneRule(const TimeZoneRule& source);
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ InitialTimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings);
+
+ /**
+ * Copy constructor.
+ * @param source The InitialTimeZoneRule object to be copied.
+ * @stable ICU 3.8
+ */
+ InitialTimeZoneRule(const InitialTimeZoneRule& source);
+
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ virtual InitialTimeZoneRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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".
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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
+ *
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ AnnualTimeZoneRule(const AnnualTimeZoneRule& source);
+
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ virtual AnnualTimeZoneRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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".
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ *
+ * @stable 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>UTC_TIME</code>.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source);
+
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ virtual TimeArrayTimeZoneRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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>UTC_TIME</code>.
+ *
+ * @return The time type used of the start times used by this rule.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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-4.8.1/i18n/unicode/tztrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tztrans.h
new file mode 100644
index 00000000000..94b8e91267a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/tztrans.h
@@ -0,0 +1,195 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ TimeZoneTransition(UDate time, const TimeZoneRule& from, const TimeZoneRule& to);
+
+ /**
+ * Constructs an empty <code>TimeZoneTransition</code>
+ * @stable ICU 3.8
+ */
+ TimeZoneTransition();
+
+ /**
+ * Copy constructor.
+ * @param source The TimeZoneTransition object to be copied.
+ * @stable ICU 3.8
+ */
+ TimeZoneTransition(const TimeZoneTransition& source);
+
+ /**
+ * Destructor.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ TimeZoneTransition* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ void setTime(UDate time);
+
+ /**
+ * Returns the rule used before the transition.
+ * @return The time zone rule used after the transition.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ void adoptTo(TimeZoneRule* to);
+
+ /**
+ * Returns the rule used after the transition.
+ * @return The time zone rule used after the transition.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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-4.8.1/i18n/unicode/ucal.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucal.h
new file mode 100644
index 00000000000..55d65d06b91
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucal.h
@@ -0,0 +1,1368 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2011, 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"
+#include "unicode/localpointer.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
+ */
+
+/**
+ * The time zone ID reserved for unknown time zone.
+ * @draft ICU 4.8
+ */
+#define UCAL_UNKNOWN_ZONE_ID "Etc/Unknown"
+
+/** A calendar.
+ * For usage in C programs.
+ * @stable ICU 2.0
+ */
+typedef void* UCalendar;
+
+/** Possible types of UCalendars
+ * @stable ICU 2.0
+ */
+enum UCalendarType {
+ /**
+ * Despite the name, UCAL_TRADITIONAL designates the locale's default calendar,
+ * which may be the Gregorian calendar or some other calendar.
+ * @stable ICU 2.0
+ */
+ UCAL_TRADITIONAL,
+ /**
+ * A better name for UCAL_TRADITIONAL.
+ * @stable ICU 4.2
+ */
+ UCAL_DEFAULT = UCAL_TRADITIONAL,
+ /**
+ * Unambiguously designates the Gregorian calendar for the locale.
+ * @stable ICU 2.0
+ */
+ 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,
+
+ /**
+ * Whether or not the current month is a leap month (0 or 1). See the Chinese calendar for
+ * an example of this.
+ */
+ UCAL_IS_LEAP_MONTH,
+
+ /**
+ * 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;
+
+/**
+ * System time zone type constants used by filtering zones
+ * in ucal_openTimeZoneIDEnumeration.
+ * @see ucal_openTimeZoneIDEnumeration
+ * @draft ICU 4.8
+ */
+enum USystemTimeZoneType {
+ /**
+ * Any system zones.
+ * @draft ICU 4.8
+ */
+ UCAL_ZONE_TYPE_ANY,
+ /**
+ * Canonical system zones.
+ * @draft ICU 4.8
+ */
+ UCAL_ZONE_TYPE_CANONICAL,
+ /**
+ * Canonical system zones associated with actual locations.
+ * @draft ICU 4.8
+ */
+ UCAL_ZONE_TYPE_CANONICAL_LOCATION
+};
+
+/** @draft ICU 4.8 */
+typedef enum USystemTimeZoneType USystemTimeZoneType;
+
+/**
+ * Create an enumeration over system time zone IDs with the given
+ * filter conditions.
+ * @param zoneType The system time zone type.
+ * @param region The ISO 3166 two-letter country code or UN M.49
+ * three-digit area code. When NULL, no filtering
+ * done by region.
+ * @param rawOffset An offset from GMT in milliseconds, ignoring the
+ * effect of daylight savings time, if any. When NULL,
+ * no filtering done by zone offset.
+ * @param ec A pointer to an UErrorCode to receive any errors
+ * @return an enumeration object that the caller must dispose of
+ * using enum_close(), or NULL upon failure. In case of failure,
+ * *ec will indicate the error.
+ * @draft ICU 4.8
+ */
+U_DRAFT UEnumeration* U_EXPORT2
+ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
+ const int32_t* rawOffset, UErrorCode* ec);
+
+/**
+ * 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.
+ * <p>
+ * Note: When unknown TimeZone ID is specified, the UCalendar returned
+ * by the function is initialized with GMT ("Etc/GMT") without any
+ * errors/warnings. If you want to check if a TimeZone ID is valid,
+ * use ucal_getCanonicalTimeZoneID prior to this function.
+ *
+ * @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. This can be UCAL_GREGORIAN to open the Gregorian
+ * calendar for the locale, or UCAL_DEFAULT to open the default calendar for the locale (the
+ * default calendar may also be Gregorian). To open a specific non-Gregorian calendar for the
+ * locale, use uloc_setKeywordValue to set the value of the calendar keyword for the locale
+ * and then pass the locale to ucal_open with UCAL_DEFAULT as the type.
+ * @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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUCalendarPointer
+ * "Smart pointer" class, closes a UCalendar via ucal_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUCalendarPointer, UCalendar, ucal_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Open a copy of a UCalendar.
+ * This function performs a deep copy.
+ * @param cal The calendar to copy
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UCalendar identical to cal.
+ * @stable ICU 4.0
+ */
+U_STABLE UCalendar* U_EXPORT2
+ucal_clone(const UCalendar* cal,
+ UErrorCode* status);
+
+/**
+ * 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 localeIndex 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 localeIndex);
+
+/**
+ * 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"
+ * @stable ICU 3.8
+ */
+U_STABLE const char * U_EXPORT2
+ucal_getTZDataVersion(UErrorCode* status);
+
+/**
+ * Returns the canonical system timezone ID or the normalized
+ * custom time zone ID for the given time zone ID.
+ * @param id The input timezone ID to be canonicalized.
+ * @param len The length of id, or -1 if null-terminated.
+ * @param result The buffer receives the canonical system timezone ID
+ * or the custom timezone ID in normalized format.
+ * @param resultCapacity The capacity of the result buffer.
+ * @param isSystemID Receives if the given ID is a known system
+ * timezone ID.
+ * @param status Recevies the status. When the given timezone ID
+ * is neither a known system time zone ID nor a
+ * valid custom timezone ID, U_ILLEGAL_ARGUMENT_ERROR
+ * is set.
+ * @return The result string length, not including the terminating
+ * null.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
+ UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status);
+/**
+ * Get the resource keyword value string designating the calendar type for the UCalendar.
+ * @param cal The UCalendar to query.
+ * @param status The error code for the operation.
+ * @return The resource keyword value string.
+ * @stable ICU 4.2
+ */
+U_STABLE const char * U_EXPORT2
+ucal_getType(const UCalendar *cal, UErrorCode* status);
+
+/**
+ * Given a key and a locale, returns an array of string values in a preferred
+ * order that would make a difference. These are all and only those values where
+ * the open (creation) of the service with the locale formed from the input locale
+ * plus input keyword and that value has different behavior than creation with the
+ * input locale alone.
+ * @param key one of the keys supported by this service. For now, only
+ * "calendar" is supported.
+ * @param locale the locale
+ * @param commonlyUsed if set to true it will return only commonly used values
+ * with the given locale in preferred order. Otherwise,
+ * it will return all the available values for the locale.
+ * @param status error status
+ * @return a string enumeration over keyword values for the given key and the locale.
+ * @stable ICU 4.2
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucal_getKeywordValuesForLocale(const char* key,
+ const char* locale,
+ UBool commonlyUsed,
+ UErrorCode* status);
+
+
+/** Weekday types, as returned by ucal_getDayOfWeekType().
+ * @stable ICU 4.4
+ */
+enum UCalendarWeekdayType {
+ /**
+ * Designates a full weekday (no part of the day is included in the weekend).
+ * @stable ICU 4.4
+ */
+ UCAL_WEEKDAY,
+ /**
+ * Designates a full weekend day (the entire day is included in the weekend).
+ * @stable ICU 4.4
+ */
+ UCAL_WEEKEND,
+ /**
+ * Designates a day that starts as a weekday and transitions to the weekend.
+ * Call ucal_getWeekendTransition() to get the time of transition.
+ * @stable ICU 4.4
+ */
+ UCAL_WEEKEND_ONSET,
+ /**
+ * Designates a day that starts as the weekend and transitions to a weekday.
+ * Call ucal_getWeekendTransition() to get the time of transition.
+ * @stable ICU 4.4
+ */
+ UCAL_WEEKEND_CEASE
+};
+
+/** @stable ICU 4.4 */
+typedef enum UCalendarWeekdayType UCalendarWeekdayType;
+
+/**
+ * Returns whether the given day of the week is a weekday, a
+ * weekend day, or a day that transitions from one to the other,
+ * in this calendar system. If a transition occurs at midnight,
+ * then the days before and after the transition will have the
+ * type UCAL_WEEKDAY or UCAL_WEEKEND. If a transition occurs at a time
+ * other than midnight, then the day of the transition will have
+ * the type UCAL_WEEKEND_ONSET or UCAL_WEEKEND_CEASE. In this case, the
+ * method getWeekendTransition() will return the point of
+ * transition.
+ * @param cal The UCalendar to query.
+ * @param dayOfWeek The day of the week whose type is desired (UCAL_SUNDAY..UCAL_SATURDAY).
+ * @param status The error code for the operation.
+ * @return The UCalendarWeekdayType for the day of the week.
+ * @stable ICU 4.4
+ */
+U_STABLE UCalendarWeekdayType U_EXPORT2
+ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status);
+
+/**
+ * Returns the time during the day at which the weekend begins or ends in
+ * this calendar system. If ucal_getDayOfWeekType() rerturns UCAL_WEEKEND_ONSET
+ * for the specified dayOfWeek, return the time at which the weekend begins.
+ * If ucal_getDayOfWeekType() returns UCAL_WEEKEND_CEASE for the specified dayOfWeek,
+ * return the time at which the weekend ends. If ucal_getDayOfWeekType() returns
+ * some other UCalendarWeekdayType for the specified dayOfWeek, is it an error condition
+ * (U_ILLEGAL_ARGUMENT_ERROR).
+ * @param cal The UCalendar to query.
+ * @param dayOfWeek The day of the week for which the weekend transition time is
+ * desired (UCAL_SUNDAY..UCAL_SATURDAY).
+ * @param status The error code for the operation.
+ * @return The milliseconds after midnight at which the weekend begins or ends.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status);
+
+/**
+ * Returns TRUE if the given UDate is in the weekend in
+ * this calendar system.
+ * @param cal The UCalendar to query.
+ * @param date The UDate in question.
+ * @param status The error code for the operation.
+ * @return TRUE if the given UDate is in the weekend in
+ * this calendar system, FALSE otherwise.
+ * @stable ICU 4.4
+ */
+U_STABLE UBool U_EXPORT2
+ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status);
+
+/**
+ * Return the difference between the target time and the time this calendar object is currently set to.
+ * If the target time is after the current calendar setting, the the returned value will be positive.
+ * The field parameter specifies the units of the return value. For example, if field is UCAL_MONTH
+ * and ucal_getFieldDifference returns 3, then the target time is 3 to less than 4 months after the
+ * current calendar setting.
+ *
+ * As a side effect of this call, this calendar is advanced toward target by the given amount. That is,
+ * calling this function has the side effect of calling ucal_add on this calendar with the specified
+ * field and an amount equal to the return value from this function.
+ *
+ * A typical way of using this function is to call it first with the largest field of interest, then
+ * with progressively smaller fields.
+ *
+ * @param cal The UCalendar to compare and update.
+ * @param target The target date to compare to the current calendar setting.
+ * @param field The field to compare; 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 date difference for the specified field.
+ * @draft ICU 4.8
+ */
+U_DRAFT int32_t U_EXPORT2
+ucal_getFieldDifference(UCalendar* cal,
+ UDate target,
+ UCalendarDateFields field,
+ UErrorCode* status);
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucol.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucol.h
new file mode 100644
index 00000000000..880df8c7a8e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucol.h
@@ -0,0 +1,1325 @@
+/*
+*******************************************************************************
+* Copyright (c) 1996-2011, 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/localpointer.h"
+#include "unicode/parseerr.h"
+#include "unicode/uloc.h"
+#include "unicode/uset.h"
+#include "unicode/uscript.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;
+
+/**
+ * Enum containing the codes for reordering segments of the collation table that are not script
+ * codes. These reordering codes are to be used in conjunction with the script codes.
+ * @see ucol_getReorderCodes
+ * @see ucol_setReorderCodes
+ * @see ucol_getEquivalentReorderCodes
+ * @draft ICU 4.8
+ */
+ typedef enum {
+ /**
+ * A special reordering code that is used to specify the default
+ * reordering codes for a locale.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_DEFAULT = -1,
+ /**
+ * A special reordering code that is used to specify no reordering codes.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_NONE = USCRIPT_UNKNOWN,
+ /**
+ * A special reordering code that is used to specify all other codes used for
+ * reordering except for the codes lised as UColReorderCode values and those
+ * listed explicitly in a reordering.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_OTHERS = USCRIPT_UNKNOWN,
+ /**
+ * Characters with the space property.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_SPACE = 0x1000,
+ /**
+ * The first entry in the enumeration of reordering groups.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_FIRST = UCOL_REORDER_CODE_SPACE,
+ /**
+ * Characters with the punctuation property.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_PUNCTUATION = 0x1001,
+ /**
+ * Characters with the symbol property.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_SYMBOL = 0x1002,
+ /**
+ * Characters with the currency property.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_CURRENCY = 0x1003,
+ /**
+ * Characters with the digit property.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_DIGIT = 0x1004,
+ /**
+ * The limit of the reorder codes.
+ * @draft ICU 4.8
+ */
+ UCOL_REORDER_CODE_LIMIT = 0x1005
+} UColReorderCode;
+
+/**
+ * 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'. Note that the longest
+ * digit substring that can be treated as a single collation element is
+ * 254 digits (not counting leading zeros). If a digit substring is
+ * longer than that, the digits beyond the limit will be treated as a
+ * separate digit substring associated with a separate collation element. */
+ 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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUCollatorPointer
+ * "Smart pointer" class, closes a UCollator via ucol_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUCollatorPointer, UCollator, ucol_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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);
+
+/**
+ * Retrieves the reordering codes for this collator.
+ * These reordering codes are a combination of UScript codes and UColReorderCode entries.
+ * @param coll The UCollator to query.
+ * @param dest The array to fill with the script ordering.
+ * @param destCapacity The length of dest. If it is 0, then dest may be NULL and the function
+ * will only return the length of the result without writing any of the result string (pre-flighting).
+ * @param pErrorCode Must be a valid pointer to an error code value, which must not indicate a
+ * failure before the function call.
+ * @return The number of reordering codes written to the dest array.
+ * @see ucol_setReorderCodes
+ * @see ucol_getEquivalentReorderCodes
+ * @draft ICU 4.8
+ */
+U_DRAFT int32_t U_EXPORT2
+ucol_getReorderCodes(const UCollator* coll,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode *pErrorCode);
+/**
+ * Sets the reordering codes for this collator.
+ * Collation reordering allows scripts and some other defined blocks of characters
+ * to be moved relative to each other as a block. This reordering is done on top of
+ * the DUCET/CLDR standard collation order. Reordering can specify groups to be placed
+ * at the start and/or the end of the collation order. These groups are specified using
+ * UScript codes and UColReorderCode entries.
+ * <p>By default, reordering codes specified for the start of the order are placed in the
+ * order given after a group of "special" non-script blocks. These special groups of characters
+ * are space, punctuation, symbol, currency, and digit. These special groups are represented with
+ * UColReorderCode entries. Script groups can be intermingled with
+ * these special non-script blocks if those special blocks are explicitly specified in the reordering.
+ * <p>The special code OTHERS stands for any script that is not explicitly
+ * mentioned in the list of reordering codes given. Anything that is after OTHERS
+ * will go at the very end of the reordering in the order given.
+ * <p>The special reorder code DEFAULT will reset the reordering for this collator
+ * to the default for this collator. The default reordering may be the DUCET/CLDR order or may be a reordering that
+ * was specified when this collator was created from resource data or from rules. The
+ * DEFAULT code <b>must</b> be the sole code supplied when it used. If not
+ * that will result in an U_ILLEGAL_ARGUMENT_ERROR being set.
+ * <p>The special reorder code NONE will remove any reordering for this collator.
+ * The result of setting no reordering will be to have the DUCET/CLDR reordering used. The
+ * NONE code <b>must</b> be the sole code supplied when it used.
+ * @param coll The UCollator to set.
+ * @param reorderCodes An array of script codes in the new order. This can be NULL if the
+ * length is also set to 0. An empty array will clear any reordering codes on the collator.
+ * @param reorderCodesLength The length of reorderCodes.
+ * @param pErrorCode Must be a valid pointer to an error code value, which must not indicate a
+ * failure before the function call.
+ * @see ucol_getReorderCodes
+ * @see ucol_getEquivalentReorderCodes
+ * @draft ICU 4.8
+ */
+U_DRAFT void U_EXPORT2
+ucol_setReorderCodes(UCollator* coll,
+ const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode *pErrorCode);
+
+/**
+ * Retrieves the reorder codes that are grouped with the given reorder code. Some reorder
+ * codes will be grouped and must reorder together.
+ * @param reorderCode The reorder code to determine equivalence for.
+ * @param dest The array to fill with the script ordering.
+ * @param destCapacity The length of dest. If it is 0, then dest may be NULL and the function
+ * will only return the length of the result without writing any of the result string (pre-flighting).
+ * @param pErrorCode Must be a valid pointer to an error code value, which must not indicate
+ * a failure before the function call.
+ * @return The number of reordering codes written to the dest array.
+ * @see ucol_setReorderCodes
+ * @see ucol_getReorderCodes
+ * @draft ICU 4.8
+ */
+U_DRAFT int32_t U_EXPORT2
+ucol_getEquivalentReorderCodes(int32_t reorderCode,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode *pErrorCode);
+
+/**
+ * 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 localeIndex 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 localeIndex);
+
+/**
+ * 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);
+
+/**
+ * Given a key and a locale, returns an array of string values in a preferred
+ * order that would make a difference. These are all and only those values where
+ * the open (creation) of the service with the locale formed from the input locale
+ * plus input keyword and that value has different behavior than creation with the
+ * input locale alone.
+ * @param key one of the keys supported by this service. For now, only
+ * "collation" is supported.
+ * @param locale the locale
+ * @param commonlyUsed if set to true it will return only commonly used values
+ * with the given locale in preferred order. Otherwise,
+ * it will return all the available values for the locale.
+ * @param status error status
+ * @return a string enumeration over keyword values for the given key and the locale.
+ * @stable ICU 4.2
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucol_getKeywordValuesForLocale(const char* key,
+ const char* locale,
+ UBool commonlyUsed,
+ 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>.
+ *
+ * Like ICU functions that write to an output buffer, the buffer contents
+ * is undefined if the buffer capacity (resultLength parameter) is too small.
+ * Unlike ICU functions that write a string to an output buffer,
+ * the terminating zero byte is counted in the sort key length.
+ * @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.
+ * If there was an internal error generating the sort key,
+ * a zero value is returned.
+ * @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);
+
+/**
+ * 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-4.8.1/i18n/unicode/ucoleitr.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucoleitr.h
new file mode 100644
index 00000000000..419cb9f7de6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucoleitr.h
@@ -0,0 +1,330 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2009, 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)
+
+/**
+ * This indicates an error has occured during processing or there are no more CEs
+ * to be returned.
+ *
+ * @internal
+ */
+#define UCOL_PROCESSED_NULLORDER ((int64_t)U_INT64_MAX)
+
+#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);
+
+/**
+ * Set the collation elements to use implicit ordering for Han
+ * even if they've been tailored. This will also force Hangul
+ * syllables to be ordered by decomposing them to their component
+ * Jamo.
+ *
+ * @param elems The UCollationElements containing the text.
+ * @param status A pointer to a UErrorCode to reveive any errors.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+ucol_forceHanImplicit(UCollationElements *elems, UErrorCode *status);
+
+/**
+ * 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 processed 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 ixLow a pointer to an int32_t to receive the iterator index before fetching the CE.
+ * @param ixHigh a pointer to an int32_t to receive the iterator index after fetching the CE.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The next collation elements ordering, otherwise returns UCOL_PROCESSED_NULLORDER
+ * if an error has occured or if the end of string has been reached
+ *
+ * @internal
+ */
+U_INTERNAL int64_t U_EXPORT2
+ucol_nextProcessed(UCollationElements *elems, int32_t *ixLow, int32_t *ixHigh, UErrorCode *status);
+
+/**
+ * Get the processed 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 ixLow A pointer to an int32_t to receive the iterator index after fetching the CE
+ * @param ixHigh A pointer to an int32_t to receiver the iterator index before fetching the CE
+ * @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
+ * UCOL_PROCESSED_NULLORDER if an error has occured or if the start of
+ * string has been reached.
+ *
+ * @internal
+ */
+U_INTERNAL int64_t U_EXPORT2
+ucol_previousProcessed(UCollationElements *elems, int32_t *ixLow, int32_t *ixHigh, 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-4.8.1/i18n/unicode/ucsdet.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucsdet.h
new file mode 100644
index 00000000000..dc492ee229e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucsdet.h
@@ -0,0 +1,370 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2010, 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/localpointer.h"
+#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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUCharsetDetectorPointer
+ * "Smart pointer" class, closes a UCharsetDetector via ucsdet_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUCharsetDetectorPointer, UCharsetDetector, ucsdet_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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-4.8.1/i18n/unicode/ucurr.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucurr.h
new file mode 100644
index 00000000000..40eb75b6ede
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ucurr.h
@@ -0,0 +1,349 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2011, 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 plural name for the given currency in the
+ * given locale. For example, the plural name for the USD
+ * currency object in the en_US locale is "US dollar" or "US dollars".
+ * @param currency null-terminated 3-letter ISO 4217 code
+ * @param locale locale in which to display currency
+ * @param isChoiceFormat fill-in set to TRUE if the returned value
+ * is a ChoiceFormat pattern; otherwise it is a static string
+ * @param pluralCount plural count
+ * @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.
+ * @stable ICU 4.2
+ */
+U_STABLE const UChar* U_EXPORT2
+ucurr_getPluralName(const UChar* currency,
+ const char* locale,
+ UBool* isChoiceFormat,
+ const char* pluralCount,
+ 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);
+
+/**
+ * Queries if the given ISO 4217 3-letter code is available on the specified date range.
+ *
+ * Note: For checking availability of a currency on a specific date, specify the date on both 'from' and 'to'
+ *
+ * When 'from' is U_DATE_MIN and 'to' is U_DATE_MAX, this method checks if the specified currency is available any time.
+ * If 'from' and 'to' are same UDate value, this method checks if the specified currency is available on that date.
+ *
+ * @param isoCode
+ * The ISO 4217 3-letter code.
+ *
+ * @param from
+ * The lower bound of the date range, inclusive. When 'from' is U_DATE_MIN, check the availability
+ * of the currency any date before 'to'
+ *
+ * @param to
+ * The upper bound of the date range, inclusive. When 'to' is U_DATE_MAX, check the availability of
+ * the currency any date after 'from'
+ *
+ * @param errorCode
+ * ICU error code
+ *
+ * @return TRUE if the given ISO 4217 3-letter code is supported on the specified date range.
+ *
+ * @draft ICU 4.8
+ */
+U_DRAFT UBool U_EXPORT2
+ucurr_isAvailable(const UChar* isoCode,
+ UDate from,
+ UDate to,
+ UErrorCode* errorCode);
+
+
+/**
+ * Finds the number of valid currency codes for the
+ * given locale and date.
+ * @param locale the locale for which to retrieve the
+ * currency count.
+ * @param date the date for which to retrieve the
+ * currency count for the given locale.
+ * @param ec error code
+ * @return the number of currency codes for the
+ * given locale and date. If 0, currency
+ * codes couldn't be found for the input
+ * values are invalid.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucurr_countCurrencies(const char* locale,
+ UDate date,
+ UErrorCode* ec);
+
+/**
+ * Finds a currency code for the given locale and date
+ * @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 date the date for which to retrieve a currency code for
+ * the given locale.
+ * @param index the index within the available list of currency codes
+ * for the given locale on the given date.
+ * @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 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucurr_forLocaleAndDate(const char* locale,
+ UDate date,
+ int32_t index,
+ UChar* buff,
+ int32_t buffCapacity,
+ UErrorCode* ec);
+
+/**
+ * Given a key and a locale, returns an array of string values in a preferred
+ * order that would make a difference. These are all and only those values where
+ * the open (creation) of the service with the locale formed from the input locale
+ * plus input keyword and that value has different behavior than creation with the
+ * input locale alone.
+ * @param key one of the keys supported by this service. For now, only
+ * "currency" is supported.
+ * @param locale the locale
+ * @param commonlyUsed if set to true it will return only commonly used values
+ * with the given locale in preferred order. Otherwise,
+ * it will return all the available values for the locale.
+ * @param status error status
+ * @return a string enumeration over keyword values for the given key and the locale.
+ * @stable ICU 4.2
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucurr_getKeywordValuesForLocale(const char* key,
+ const char* locale,
+ UBool commonlyUsed,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udat.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udat.h
new file mode 100644
index 00000000000..d480c7da514
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udat.h
@@ -0,0 +1,997 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, 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/localpointer.h"
+#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;
+
+
+/**
+ * @{
+ * Below are a set of pre-defined skeletons.
+ *
+ * <P>
+ * A skeleton
+ * <ol>
+ * <li>
+ * only keeps the field pattern letter and ignores all other parts
+ * in a pattern, such as space, punctuations, and string literals.
+ * </li>
+ * <li>
+ * hides the order of fields.
+ * </li>
+ * <li>
+ * might hide a field's pattern letter length.
+ *
+ * For those non-digit calendar fields, the pattern letter length is
+ * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
+ * and the field's pattern letter length is honored.
+ *
+ * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
+ * the field pattern length is ignored and the best match, which is defined
+ * in date time patterns, will be returned without honor the field pattern
+ * letter length in skeleton.
+ * </li>
+ * </ol>
+ *
+ * @stable ICU 4.0
+ */
+
+#define UDAT_MINUTE_SECOND "ms"
+#define UDAT_HOUR24_MINUTE "Hm"
+#define UDAT_HOUR24_MINUTE_SECOND "Hms"
+#define UDAT_HOUR_MINUTE_SECOND "hms"
+#define UDAT_STANDALONE_MONTH "LLLL"
+#define UDAT_ABBR_STANDALONE_MONTH "LLL"
+#define UDAT_YEAR_QUARTER "yQQQ"
+#define UDAT_YEAR_ABBR_QUARTER "yQ"
+
+/** @} */
+
+/**
+ * @{
+ * Below are a set of pre-defined skeletons that
+ * have pre-defined interval patterns in resource files.
+ * Users are encouraged to use them in date interval format factory methods.
+ *
+ * @stable ICU 4.0
+ */
+#define UDAT_HOUR_MINUTE "hm"
+#define UDAT_YEAR "y"
+#define UDAT_DAY "d"
+#define UDAT_NUM_MONTH_WEEKDAY_DAY "MEd"
+#define UDAT_YEAR_NUM_MONTH "yM"
+#define UDAT_NUM_MONTH_DAY "Md"
+#define UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY "yMEd"
+#define UDAT_ABBR_MONTH_WEEKDAY_DAY "MMMEd"
+#define UDAT_YEAR_MONTH "yMMMM"
+#define UDAT_YEAR_ABBR_MONTH "yMMM"
+#define UDAT_MONTH_DAY "MMMMd"
+#define UDAT_ABBR_MONTH_DAY "MMMd"
+#define UDAT_MONTH_WEEKDAY_DAY "MMMMEEEEd"
+#define UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY "yMMMEd"
+#define UDAT_YEAR_MONTH_WEEKDAY_DAY "yMMMMEEEEd"
+#define UDAT_YEAR_MONTH_DAY "yMMMMd"
+#define UDAT_YEAR_ABBR_MONTH_DAY "yMMMd"
+#define UDAT_YEAR_NUM_MONTH_DAY "yMd"
+#define UDAT_NUM_MONTH "M"
+#define UDAT_ABBR_MONTH "MMM"
+#define UDAT_MONTH "MMMM"
+#define UDAT_HOUR_MINUTE_GENERIC_TZ "hmv"
+#define UDAT_HOUR_MINUTE_TZ "hmz"
+#define UDAT_HOUR "h"
+#define UDAT_HOUR_GENERIC_TZ "hv"
+#define UDAT_HOUR_TZ "hz"
+
+/** @} */
+
+
+/**
+ * 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_DOW_LOCAL} 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;
+
+
+/**
+ * Maps from a UDateFormatField to the corresponding UCalendarDateFields.
+ * Note: since the mapping is many-to-one, there is no inverse mapping.
+ * @param field the UDateFormatField.
+ * @return the UCalendarDateField. This will be UCAL_FIELD_COUNT in case
+ * of error (e.g., the input field is UDAT_FIELD_COUNT).
+ * @stable ICU 4.4
+ */
+U_STABLE UCalendarDateFields U_EXPORT2
+udat_toCalendarDateField(UDateFormatField field);
+
+
+/**
+ * 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, UDAT_DEFAULT, or UDAT_NONE (relative time styles
+ * are not currently supported)
+ * @param dateStyle The style used to format dates; one of UDAT_FULL, UDAT_LONG,
+ * UDAT_MEDIUM, UDAT_SHORT, UDAT_DEFAULT, UDAT_FULL_RELATIVE, UDAT_LONG_RELATIVE,
+ * UDAT_MEDIUM_RELATIVE, UDAT_SHORT_RELATIVE, or UDAT_NONE
+ * @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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUDateFormatPointer
+ * "Smart pointer" class, closes a UDateFormat via udat_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUDateFormatPointer, UDateFormat, udat_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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 localeIndex 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 localeIndex);
+
+/**
+* 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 symbolIndex 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 symbolIndex,
+ 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 symbolIndex 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 symbolIndex,
+ 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);
+
+/**
+* Extract the date pattern from a UDateFormat set for relative date formatting.
+* The pattern will follow the pattern syntax rules.
+* @param fmt The formatter to query.
+* @param result A pointer to a buffer to receive the pattern.
+* @param resultLength The maximum size of result.
+* @param status A pointer to a UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see udat_applyPatternRelative
+* @internal ICU 4.2 technology preview
+*/
+U_INTERNAL int32_t U_EXPORT2
+udat_toPatternRelativeDate(const UDateFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status);
+
+/**
+* Extract the time pattern from a UDateFormat set for relative date formatting.
+* The pattern will follow the pattern syntax rules.
+* @param fmt The formatter to query.
+* @param result A pointer to a buffer to receive the pattern.
+* @param resultLength The maximum size of result.
+* @param status A pointer to a UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see udat_applyPatternRelative
+* @internal ICU 4.2 technology preview
+*/
+U_INTERNAL int32_t U_EXPORT2
+udat_toPatternRelativeTime(const UDateFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status);
+
+/**
+* Set the date & time patterns used by a UDateFormat set for relative date formatting.
+* The patterns should follow the pattern syntax rules.
+* @param format The formatter to set.
+* @param datePattern The new date pattern
+* @param datePatternLength The length of datePattern, or -1 if null-terminated.
+* @param timePattern The new time pattern
+* @param timePatternLength The length of timePattern, or -1 if null-terminated.
+* @param status A pointer to a UErrorCode to receive any errors
+* @see udat_toPatternRelativeDate, udat_toPatternRelativeTime
+* @internal ICU 4.2 technology preview
+*/
+U_INTERNAL void U_EXPORT2
+udat_applyPatternRelative(UDateFormat *format,
+ const UChar *datePattern,
+ int32_t datePatternLength,
+ const UChar *timePattern,
+ int32_t timePatternLength,
+ UErrorCode *status);
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udateintervalformat.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udateintervalformat.h
new file mode 100644
index 00000000000..4a4230a98eb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udateintervalformat.h
@@ -0,0 +1,178 @@
+/*
+*****************************************************************************************
+* Copyright (C) 2010-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*****************************************************************************************
+*/
+
+#ifndef UDATEINTERVALFORMAT_H
+#define UDATEINTERVALFORMAT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/umisc.h"
+#include "unicode/localpointer.h"
+
+/**
+ * A UDateIntervalFormat is used to format the range between two UDate values
+ * in a locale-sensitive way, using a skeleton that specifies the precision and
+ * completeness of the information to show. If the range smaller than the resolution
+ * specified by the skeleton, a single date format will be produced. If the range
+ * is larger than the format specified by the skeleton, a locale-specific fallback
+ * will be used to format the items missing from the skeleton.
+ *
+ * For example, if the range is 2010-03-04 07:56 - 2010-03-04 19:56 (12 hours)
+ * - The skeleton jm will produce
+ * for en_US, "7:56 AM - 7:56 PM"
+ * for en_GB, "7:56 - 19:56"
+ * - The skeleton MMMd will produce
+ * for en_US, "Mar 4"
+ * for en_GB, "4 Mar"
+ * If the range is 2010-03-04 07:56 - 2010-03-08 16:11 (4 days, 8 hours, 15 minutes)
+ * - The skeleton jm will produce
+ * for en_US, "3/4/2010 7:56 AM - 3/8/2010 4:11 PM"
+ * for en_GB, "4/3/2010 7:56 - 8/3/2010 16:11"
+ * - The skeleton MMMd will produce
+ * for en_US, "Mar 4-8"
+ * for en_GB, "4-8 Mar"
+ *
+ * Note: the "-" characters in the above sample output will actually be
+ * Unicode 2013, EN_DASH, in all but the last example.
+ *
+ * Note, in ICU 4.4 the standard skeletons for which date interval format data
+ * is usually available are as follows; best results will be obtained by using
+ * skeletons from this set, or those formed by combining these standard skeletons
+ * (note that for these skeletons, the length of digit field such as d, y, or
+ * M vs MM is irrelevant (but for non-digit fields such as MMM vs MMMM it is
+ * relevant). Note that a skeleton involving h or H generally explicitly requests
+ * that time style (12- or 24-hour time respectively). For a skeleton that
+ * requests the locale's default time style (h or H), use 'j' instead of h or H.
+ * h, H, hm, Hm,
+ * hv, Hv, hmv, Hmv,
+ * d,
+ * M, MMM, MMMM,
+ * Md, MMMd,
+ * MEd, MMMEd,
+ * y,
+ * yM, yMMM, yMMMM,
+ * yMd, yMMMd,
+ * yMEd, yMMMEd
+ *
+ * Locales for which ICU 4.4 seems to have a reasonable amount of this data
+ * include:
+ * af, am, ar, be, bg, bn, ca, cs, da, de (_AT), el, en (_AU,_CA,_GB,_IE,_IN...),
+ * eo, es (_AR,_CL,_CO,...,_US) et, fa, fi, fo, fr (_BE,_CH,_CA), fur, gsw, he,
+ * hr, hu, hy, is, it (_CH), ja, kk, km, ko, lt, lv, mk, ml, mt, nb, nl )_BE),
+ * nn, pl, pt (_PT), rm, ro, ru (_UA), sk, sl, so, sq, sr, sr_Latn, sv, th, to,
+ * tr, uk, ur, vi, zh (_SG), zh_Hant (_HK,_MO)
+ */
+
+/**
+ * Opaque UDateIntervalFormat object for use in C programs.
+ * @draft ICU 4.8
+ */
+struct UDateIntervalFormat;
+typedef struct UDateIntervalFormat UDateIntervalFormat; /**< C typedef for struct UDateIntervalFormat. @draft ICU 4.8 */
+
+/**
+ * Open a new UDateIntervalFormat object using the predefined rules for a
+ * given locale plus a specified skeleton.
+ * @param locale
+ * The locale for whose rules should be used; may be NULL for
+ * default locale.
+ * @param skeleton
+ * A pattern containing only the fields desired for the interval
+ * format, for example "Hm", "yMMMd", or "yMMMEdHm".
+ * @param skeletonLength
+ * The length of skeleton; may be -1 if the skeleton is zero-terminated.
+ * @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. If 0, use the default
+ * timezone.
+ * @param status
+ * A pointer to a UErrorCode to receive any errors.
+ * @return
+ * A pointer to a UDateIntervalFormat object for the specified locale,
+ * or NULL if an error occurred.
+ * @draft ICU 4.8
+ */
+U_DRAFT UDateIntervalFormat* U_EXPORT2
+udtitvfmt_open(const char* locale,
+ const UChar* skeleton,
+ int32_t skeletonLength,
+ const UChar* tzID,
+ int32_t tzIDLength,
+ UErrorCode* status);
+
+/**
+ * Close a UDateIntervalFormat object. Once closed it may no longer be used.
+ * @param formatter
+ * The UDateIntervalFormat object to close.
+ * @draft ICU 4.8
+ */
+U_DRAFT void U_EXPORT2
+udtitvfmt_close(UDateIntervalFormat *formatter);
+
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUDateIntervalFormatPointer
+ * "Smart pointer" class, closes a UDateIntervalFormat via udtitvfmt_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @draft ICU 4.8
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUDateIntervalFormatPointer, UDateIntervalFormat, udtitvfmt_close);
+
+U_NAMESPACE_END
+
+#endif
+
+
+/**
+ * Formats a date/time range using the conventions established for the
+ * UDateIntervalFormat object.
+ * @param formatter
+ * The UDateIntervalFormat object specifying the format conventions.
+ * @param fromDate
+ * The starting point of the range.
+ * @param toDate
+ * The ending point of the range.
+ * @param result
+ * A pointer to a buffer to receive the formatted range.
+ * @param resultCapacity
+ * 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 a UErrorCode to receive any errors.
+ * @return
+ * The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @draft ICU 4.8
+ */
+U_DRAFT int32_t U_EXPORT2
+udtitvfmt_format(const UDateIntervalFormat* formatter,
+ UDate fromDate,
+ UDate toDate,
+ UChar* result,
+ int32_t resultCapacity,
+ UFieldPosition* position,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udatpg.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udatpg.h
new file mode 100644
index 00000000000..3dc7e89f2df
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/udatpg.h
@@ -0,0 +1,586 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2007-2010, 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"
+#include "unicode/localpointer.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.
+ * @stable ICU 3.8
+ */
+typedef void *UDateTimePatternGenerator;
+
+/**
+ * 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.
+ * @stable ICU 3.8
+ */
+typedef enum UDateTimePatternField {
+ /** @stable ICU 3.8 */
+ UDATPG_ERA_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_YEAR_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_QUARTER_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_MONTH_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_WEEK_OF_YEAR_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_WEEK_OF_MONTH_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_WEEKDAY_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_DAY_OF_YEAR_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_DAY_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_DAYPERIOD_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_HOUR_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_MINUTE_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_SECOND_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_FRACTIONAL_SECOND_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_ZONE_FIELD,
+ /** @stable ICU 3.8 */
+ UDATPG_FIELD_COUNT
+} UDateTimePatternField;
+
+/**
+ * Masks to control forcing the length of specified fields in the returned
+ * pattern to match those in the skeleton (when this would not happen
+ * otherwise). These may be combined to force the length of multiple fields.
+ * Used with udatpg_getBestPatternWithOptions, udatpg_replaceFieldTypesWithOptions.
+ * @stable ICU 4.4
+ */
+typedef enum UDateTimePatternMatchOptions {
+ /** @stable ICU 4.4 */
+ UDATPG_MATCH_NO_OPTIONS = 0,
+ /** @stable ICU 4.4 */
+ UDATPG_MATCH_HOUR_FIELD_LENGTH = 1 << UDATPG_HOUR_FIELD,
+ /** @internal ICU 4.4 */
+ UDATPG_MATCH_MINUTE_FIELD_LENGTH = 1 << UDATPG_MINUTE_FIELD,
+ /** @internal ICU 4.4 */
+ UDATPG_MATCH_SECOND_FIELD_LENGTH = 1 << UDATPG_SECOND_FIELD,
+ /** @stable ICU 4.4 */
+ UDATPG_MATCH_ALL_FIELDS_LENGTH = (1 << UDATPG_FIELD_COUNT) - 1
+} UDateTimePatternMatchOptions;
+
+/**
+ * Status return values from udatpg_addPattern().
+ * @stable ICU 3.8
+ */
+typedef enum UDateTimePatternConflict {
+ /** @stable ICU 3.8 */
+ UDATPG_NO_CONFLICT,
+ /** @stable ICU 3.8 */
+ UDATPG_BASE_CONFLICT,
+ /** @stable ICU 3.8 */
+ UDATPG_CONFLICT,
+ /** @stable ICU 3.8 */
+ UDATPG_CONFLICT_COUNT
+} UDateTimePatternConflict;
+
+/**
+ * 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE UDateTimePatternGenerator * U_EXPORT2
+udatpg_openEmpty(UErrorCode *pErrorCode);
+
+/**
+ * Close a generator.
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @stable ICU 3.8
+ */
+U_STABLE void U_EXPORT2
+udatpg_close(UDateTimePatternGenerator *dtpg);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUDateTimePatternGeneratorPointer
+ * "Smart pointer" class, closes a UDateTimePatternGenerator via udatpg_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUDateTimePatternGeneratorPointer, UDateTimePatternGenerator, udatpg_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE int32_t U_EXPORT2
+udatpg_getBestPattern(UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t length,
+ UChar *bestPattern, int32_t capacity,
+ 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 options
+ * Options for forcing the length of specified fields in the
+ * returned pattern to match those in the skeleton (when this
+ * would not happen otherwise). For default behavior, use
+ * UDATPG_MATCH_NO_OPTIONS.
+ * @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.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+udatpg_getBestPatternWithOptions(UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t length,
+ UDateTimePatternMatchOptions options,
+ 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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);
+
+/**
+ * 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 options
+ * Options controlling whether the length of specified fields in the
+ * pattern are adjusted to match those in the skeleton (when this
+ * would not happen otherwise). For default behavior, use
+ * UDATPG_MATCH_NO_OPTIONS.
+ * @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.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+udatpg_replaceFieldTypesWithOptions(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t patternLength,
+ const UChar *skeleton, int32_t skeletonLength,
+ UDateTimePatternMatchOptions options,
+ 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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.
+ * @stable ICU 3.8
+ */
+U_STABLE 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-4.8.1/i18n/unicode/uldnames.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uldnames.h
new file mode 100644
index 00000000000..4a119ea2653
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uldnames.h
@@ -0,0 +1,270 @@
+/*
+*******************************************************************************
+* Copyright (C) 2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef __ULDNAMES_H__
+#define __ULDNAMES_H__
+
+/**
+ * \file
+ * \brief C++ API: Provides display names of Locale ids and their components.
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+#include "unicode/uscript.h"
+
+/**
+ * Enum used in LocaleDisplayNames::createInstance.
+ * @stable ICU 4.4
+ */
+typedef enum {
+ /**
+ * Use standard names when generating a locale name,
+ * e.g. en_GB displays as 'English (United Kingdom)'.
+ * @stable ICU 4.4
+ */
+ ULDN_STANDARD_NAMES = 0,
+ /**
+ * Use dialect names, when generating a locale name,
+ * e.g. en_GB displays as 'British English'.
+ * @stable ICU 4.4
+ */
+ ULDN_DIALECT_NAMES
+} UDialectHandling;
+
+/**
+ * Opaque C service object type for the locale display names API
+ * @stable ICU 4.4
+ */
+struct ULocaleDisplayNames;
+
+/**
+ * C typedef for struct ULocaleDisplayNames.
+ * @stable ICU 4.4
+ */
+typedef struct ULocaleDisplayNames ULocaleDisplayNames;
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * Returns an instance of LocaleDisplayNames that returns names
+ * formatted for the provided locale, using the provided
+ * dialectHandling. The usual value for dialectHandling is
+ * ULOC_STANDARD_NAMES.
+ *
+ * @param locale the display locale
+ * @param dialectHandling how to select names for locales
+ * @return a ULocaleDisplayNames instance
+ * @param pErrorCode the status code
+ * @stable ICU 4.4
+ */
+U_STABLE ULocaleDisplayNames * U_EXPORT2
+uldn_open(const char * locale,
+ UDialectHandling dialectHandling,
+ UErrorCode *pErrorCode);
+
+/**
+ * Closes a ULocaleDisplayNames instance obtained from uldn_open().
+ * @param ldn the ULocaleDisplayNames instance to be closed
+ * @stable ICU 4.4
+ */
+U_STABLE void U_EXPORT2
+uldn_close(ULocaleDisplayNames *ldn);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalULocaleDisplayNamesPointer
+ * "Smart pointer" class, closes a ULocaleDisplayNames via uldn_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalULocaleDisplayNamesPointer, ULocaleDisplayNames, uldn_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/* getters for state */
+
+/**
+ * Returns the locale used to determine the display names. This is
+ * not necessarily the same locale passed to {@link #uldn_open}.
+ * @param ldn the LocaleDisplayNames instance
+ * @return the display locale
+ * @stable ICU 4.4
+ */
+U_STABLE const char * U_EXPORT2
+uldn_getLocale(const ULocaleDisplayNames *ldn);
+
+/**
+ * Returns the dialect handling used in the display names.
+ * @param ldn the LocaleDisplayNames instance
+ * @return the dialect handling enum
+ * @stable ICU 4.4
+ */
+U_STABLE UDialectHandling U_EXPORT2
+uldn_getDialectHandling(const ULocaleDisplayNames *ldn);
+
+/* names for entire locales */
+
+/**
+ * Returns the display name of the provided locale.
+ * @param ldn the LocaleDisplayNames instance
+ * @param locale the locale whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_localeDisplayName(const ULocaleDisplayNames *ldn,
+ const char *locale,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/* names for components of a locale */
+
+/**
+ * Returns the display name of the provided language code.
+ * @param ldn the LocaleDisplayNames instance
+ * @param lang the language code whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_languageDisplayName(const ULocaleDisplayNames *ldn,
+ const char *lang,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/**
+ * Returns the display name of the provided script.
+ * @param ldn the LocaleDisplayNames instance
+ * @param script the script whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_scriptDisplayName(const ULocaleDisplayNames *ldn,
+ const char *script,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/**
+ * Returns the display name of the provided script code.
+ * @param ldn the LocaleDisplayNames instance
+ * @param scriptCode the script code whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_scriptCodeDisplayName(const ULocaleDisplayNames *ldn,
+ UScriptCode scriptCode,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/**
+ * Returns the display name of the provided region code.
+ * @param ldn the LocaleDisplayNames instance
+ * @param region the region code whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_regionDisplayName(const ULocaleDisplayNames *ldn,
+ const char *region,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/**
+ * Returns the display name of the provided variant
+ * @param ldn the LocaleDisplayNames instance
+ * @param variant the variant whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_variantDisplayName(const ULocaleDisplayNames *ldn,
+ const char *variant,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/**
+ * Returns the display name of the provided locale key
+ * @param ldn the LocaleDisplayNames instance
+ * @param key the locale key whose display name to return
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_keyDisplayName(const ULocaleDisplayNames *ldn,
+ const char *key,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+/**
+ * Returns the display name of the provided value (used with the provided key).
+ * @param ldn the LocaleDisplayNames instance
+ * @param key the locale key
+ * @param value the locale key's value
+ * @param result receives the display name
+ * @param maxResultSize the size of the result buffer
+ * @param pErrorCode the status code
+ * @return the actual buffer size needed for the display name. If it's
+ * greater than maxResultSize, the returned name will be truncated.
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+uldn_keyValueDisplayName(const ULocaleDisplayNames *ldn,
+ const char *key,
+ const char *value,
+ UChar *result,
+ int32_t maxResultSize,
+ UErrorCode *pErrorCode);
+
+
+#endif /* !UCONFIG_NO_FORMATTING */
+#endif /* __ULDNAMES_H__ */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ulocdata.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ulocdata.h
new file mode 100644
index 00000000000..5de71f7fc4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/ulocdata.h
@@ -0,0 +1,275 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2011, 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"
+#include "unicode/localpointer.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 {
+ /** Basic set @stable ICU 3.4 */
+ ULOCDATA_ES_STANDARD=0,
+ /** Auxiliary set @stable ICU 3.4 */
+ ULOCDATA_ES_AUXILIARY=1,
+ /** Index Character set @draft ICU 4.8 */
+ ULOCDATA_ES_INDEX=2,
+ /** One higher than the last valid type @stable ICU 3.4 */
+ ULOCDATA_ES_COUNT=3
+} ULocaleDataExemplarSetType;
+
+/** The possible types of delimiters.
+ * @stable ICU 3.4
+ */
+typedef enum ULocaleDataDelimiterType {
+ /** Quotation start @stable ICU 3.4 */
+ ULOCDATA_QUOTATION_START = 0,
+ /** Quotation end @stable ICU 3.4 */
+ ULOCDATA_QUOTATION_END = 1,
+ /** Alternate quotation start @stable ICU 3.4 */
+ ULOCDATA_ALT_QUOTATION_START = 2,
+ /** Alternate quotation end @stable ICU 3.4 */
+ ULOCDATA_ALT_QUOTATION_END = 3,
+ /** One higher than the last valid type @stable ICU 3.4 */
+ 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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalULocaleDataPointer
+ * "Smart pointer" class, closes a ULocaleData via ulocdata_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalULocaleDataPointer, ULocaleData, ulocdata_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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. Will be set to U_MISSING_RESOURCE_ERROR
+ * if the requested data is not available.
+ * @return USet* Either fillIn, or if fillIn is NULL, a pointer to
+ * a newly-allocated USet that the user must close.
+ * In case of error, NULL is returned.
+ * @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);
+
+/**
+ * Return the current CLDR version used by the library.
+ * @param versionArray fillin that will recieve the version number
+ * @param status error code - could be U_MISSING_RESOURCE_ERROR if the version was not found.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode *status);
+
+/**
+ * Returns locale display pattern associated with a locale.
+ *
+ * @param uld Pointer to the locale data object from which the
+ * exemplar character set is to be retrieved.
+ * @param pattern locale display pattern for locale.
+ * @param patternCapacity the size of the buffer to store the locale display
+ * pattern with.
+ * @param status Must be a valid pointer to an error code value,
+ * which must not indicate a failure before the function call.
+ * @return the actual buffer size needed for localeDisplayPattern. If it's greater
+ * than patternCapacity, the returned pattern will be truncated.
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+ulocdata_getLocaleDisplayPattern(ULocaleData *uld,
+ UChar *pattern,
+ int32_t patternCapacity,
+ UErrorCode *status);
+
+
+/**
+ * Returns locale separator associated with a locale.
+ *
+ * @param uld Pointer to the locale data object from which the
+ * exemplar character set is to be retrieved.
+ * @param separator locale separator for locale.
+ * @param separatorCapacity the size of the buffer to store the locale
+ * separator with.
+ * @param status Must be a valid pointer to an error code value,
+ * which must not indicate a failure before the function call.
+ * @return the actual buffer size needed for localeSeparator. If it's greater
+ * than separatorCapacity, the returned separator will be truncated.
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+ulocdata_getLocaleSeparator(ULocaleData *uld,
+ UChar *separator,
+ int32_t separatorCapacity,
+ UErrorCode *status);
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/umsg.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/umsg.h
new file mode 100644
index 00000000000..52fe90e2d6a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/umsg.h
@@ -0,0 +1,623 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Copyright (C) 2010 , Yahoo! Inc.
+ ********************************************************************
+ *
+ * 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/localpointer.h"
+#include "unicode/uloc.h"
+#include "unicode/parseerr.h"
+#include <stdarg.h>
+
+/**
+ * \file
+ * \brief C API: MessageFormat
+ *
+ * <h2>MessageFormat C API </h2>
+ *
+ * <p>MessageFormat prepares strings for display to users,
+ * with optional arguments (variables/placeholders).
+ * The arguments can occur in any order, which is necessary for translation
+ * into languages with different grammars.
+ *
+ * <p>The opaque UMessageFormat type is a thin C wrapper around
+ * a C++ MessageFormat. It is constructed from a <em>pattern</em> string
+ * with arguments in {curly braces} which will be replaced by formatted values.
+ *
+ * <p>Currently, the C API supports only numbered arguments.
+ *
+ * <p>For details about the pattern syntax and behavior,
+ * especially about the ASCII apostrophe vs. the
+ * real apostrophe (single quote) character \htmlonly&#x2019;\endhtmlonly (U+2019),
+ * see the C++ MessageFormat class documentation.
+ *
+ * <p>Here are some examples of C API 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>
+ *
+ *
+ * Example 3:
+ * <pre>
+ * \code
+ * UChar* str;
+ * UChar* str1;
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar *result;
+ * UChar pattern[100];
+ * UChar expected[100];
+ * int32_t resultlength,resultLengthOut;
+
+ * str=(UChar*)malloc(sizeof(UChar) * 25);
+ * u_uastrcpy(str, "Kirti");
+ * str1=(UChar*)malloc(sizeof(UChar) * 25);
+ * u_uastrcpy(str1, "female");
+ * log_verbose("Testing message format with Select test #1\n:");
+ * u_uastrcpy(pattern, "{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
+ * u_uastrcpy(expected, "Kirti est all\\u00E9e \\u00E0 Paris.");
+ * resultlength=0;
+ * resultLengthOut=u_formatMessage( "fr", pattern, u_strlen(pattern), NULL, resultlength, &status, str , str1);
+ * if(status==U_BUFFER_OVERFLOW_ERROR)
+ * {
+ * status=U_ZERO_ERROR;
+ * resultlength=resultLengthOut+1;
+ * result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ * u_formatMessage( "fr", pattern, u_strlen(pattern), result, resultlength, &status, str , str1);
+ * if(u_strcmp(result, expected)==0)
+ * log_verbose("PASS: MessagFormat successful on Select test#1\n");
+ * else{
+ * log_err("FAIL: Error in MessageFormat on Select test#1\n GOT %s EXPECTED %s\n", austrdup(result),
+ * austrdup(expected) );
+ * }
+ * free(result);
+ * }
+ * \endcode
+ * </pre>
+ */
+
+/**
+ * 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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUMessageFormatPointer
+ * "Smart pointer" class, closes a UMessageFormat via umsg_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUMessageFormatPointer, UMessageFormat, umsg_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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-4.8.1/i18n/unicode/unirepl.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/unirepl.h
new file mode 100644
index 00000000000..6b7746b2213
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/unicode/unum.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/unum.h
new file mode 100644
index 00000000000..763fb86166d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/unum.h
@@ -0,0 +1,1053 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, 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/localpointer.h"
+#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 UNUM_DECIMAL to get the normal number format for that country.
+ * There are other static options available. Use UNUM_CURRENCY
+ * to get the currency number format for that country. Use UNUM_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 a pattern string.
+ * @stable ICU 3.0
+ */
+ UNUM_PATTERN_DECIMAL=0,
+ /**
+ * Decimal format ("normal" style).
+ * @stable ICU 2.0
+ */
+ UNUM_DECIMAL=1,
+ /**
+ * Currency format with a currency symbol, e.g., "$1.00".
+ * @stable ICU 2.0
+ */
+ UNUM_CURRENCY,
+ /**
+ * Percent format
+ * @stable ICU 2.0
+ */
+ UNUM_PERCENT,
+ /**
+ * Scientific format
+ * @stable ICU 2.1
+ */
+ UNUM_SCIENTIFIC,
+ /**
+ * Spellout rule-based format
+ * @stable ICU 2.0
+ */
+ UNUM_SPELLOUT,
+ /**
+ * Ordinal rule-based format
+ * @stable ICU 3.0
+ */
+ UNUM_ORDINAL,
+ /**
+ * Duration rule-based format
+ * @stable ICU 3.0
+ */
+ UNUM_DURATION,
+ /**
+ * Numbering system rule-based format
+ * @stable ICU 4.2
+ */
+ UNUM_NUMBERING_SYSTEM,
+ /**
+ * Rule-based format defined by a pattern string.
+ * @stable ICU 3.0
+ */
+ UNUM_PATTERN_RULEBASED,
+ /**
+ * Currency format with an ISO currency code, e.g., "USD1.00".
+ * @draft ICU 4.8
+ */
+ UNUM_CURRENCY_ISO,
+ /**
+ * Currency format with a pluralized currency name,
+ * e.g., "1.00 US dollar" and "3.00 US dollars".
+ * @draft ICU 4.8
+ */
+ UNUM_CURRENCY_PLURAL,
+ /**
+ * One more than the highest number format style constant.
+ * @draft ICU 4.8
+ */
+ UNUM_FORMAT_STYLE_COUNT,
+ /**
+ * Default format
+ * @stable ICU 2.0
+ */
+ UNUM_DEFAULT = UNUM_DECIMAL,
+ /**
+ * Alias for UNUM_PATTERN_DECIMAL
+ * @stable ICU 3.0
+ */
+ 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,
+ /**
+ * ROUND_UNNECESSARY reports an error if formatted result is not exact.
+ * @draft ICU 4.8
+ */
+ UNUM_ROUND_UNNECESSARY,
+ /**
+ * 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;
+
+/**
+ * Constants for specifying currency spacing
+ * @draft ICU 4.8
+ */
+enum UCurrencySpacing {
+ UNUM_CURRENCY_MATCH,
+ UNUM_CURRENCY_SURROUNDING_MATCH,
+ UNUM_CURRENCY_INSERT,
+ UNUM_CURRENCY_SPACING_COUNT
+};
+typedef enum UCurrencySpacing UCurrencySpacing; /**< @draft ICU 4.8 */
+
+/**
+ * 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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUNumberFormatPointer
+ * "Smart pointer" class, closes a UNumberFormat via unum_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUNumberFormatPointer, UNumberFormat, unum_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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 decimal number using a UNumberFormat.
+* The number will be formatted according to the UNumberFormat's locale.
+* The syntax of the input number is a "numeric string"
+* as defined in the Decimal Arithmetic Specification, available at
+* http://speleotrove.com/decimal
+* @param fmt The formatter to use.
+* @param number The number to format.
+* @param length The length of the input number, or -1 if the input is nul-terminated.
+* @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 it is ignored.
+* @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 4.4
+*/
+U_STABLE int32_t U_EXPORT2
+unum_formatDecimal( const UNumberFormat* fmt,
+ const char * number,
+ int32_t length,
+ 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 number from a string into an unformatted numeric string using a UNumberFormat.
+* The input string will be parsed according to the UNumberFormat's locale.
+* The syntax of the output is a "numeric string"
+* as defined in the Decimal Arithmetic Specification, available at
+* http://speleotrove.com/decimal
+* @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 outBuf A (char *) buffer to receive the parsed number as a string. The output string
+* will be nul-terminated if there is sufficient space.
+* @param outBufLength The size of the output buffer. May be zero, in which case
+* the outBuf pointer may be NULL, and the function will return the
+* size of the output string.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return the length of the output string, not including any terminating nul.
+* @see unum_parse
+* @see unum_parseInt64
+* @see unum_format
+* @see unum_formatInt64
+* @see unum_formatDouble
+* @stable ICU 4.4
+*/
+U_STABLE int32_t U_EXPORT2
+unum_parseDecimal(const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ char *outBuf,
+ int32_t outBufLength,
+ 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 localeIndex 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 localeIndex);
+
+/**
+* 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,
+ /** One
+ * @draft ICU 4.6
+ */
+ UNUM_ONE_DIGIT_SYMBOL = 18,
+ /** Two
+ * @draft ICU 4.6
+ */
+ UNUM_TWO_DIGIT_SYMBOL = 19,
+ /** Three
+ * @draft ICU 4.6
+ */
+ UNUM_THREE_DIGIT_SYMBOL = 20,
+ /** Four
+ * @draft ICU 4.6
+ */
+ UNUM_FOUR_DIGIT_SYMBOL = 21,
+ /** Five
+ * @draft ICU 4.6
+ */
+ UNUM_FIVE_DIGIT_SYMBOL = 22,
+ /** Six
+ * @draft ICU 4.6
+ */
+ UNUM_SIX_DIGIT_SYMBOL = 23,
+ /** Seven
+ * @draft ICU 4.6
+ */
+ UNUM_SEVEN_DIGIT_SYMBOL = 24,
+ /** Eight
+ * @draft ICU 4.6
+ */
+ UNUM_EIGHT_DIGIT_SYMBOL = 25,
+ /** Nine
+ * @draft ICU 4.6
+ */
+ UNUM_NINE_DIGIT_SYMBOL = 26,
+ /** count symbol constants */
+ UNUM_FORMAT_SYMBOL_COUNT = 27
+} 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-4.8.1/i18n/unicode/upluralrules.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/upluralrules.h
new file mode 100644
index 00000000000..93c7bf31f16
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/upluralrules.h
@@ -0,0 +1,104 @@
+/*
+*****************************************************************************************
+* Copyright (C) 2010-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*****************************************************************************************
+*/
+
+#ifndef UPLURALRULES_H
+#define UPLURALRULES_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/localpointer.h"
+
+/**
+ * A UPluralRules object defines rules for mapping non-negative numeric
+ * values onto a small set of keywords. Rules are constructed from a text
+ * description, consisting of a series of keywords and conditions.
+ * The uplrules_select function examines each condition in order and
+ * returns the keyword for the first condition that matches the number.
+ * If none match, the default rule(other) is returned.
+ *
+ * For more information, see the LDML spec, C.11 Language Plural Rules:
+ * http://www.unicode.org/reports/tr35/#Language_Plural_Rules
+ *
+ * Keywords: ICU locale data has 6 predefined values -
+ * 'zero', 'one', 'two', 'few', 'many' and 'other'. Callers need to check
+ * the value of keyword returned by the uplrules_select function.
+ *
+ * These are based on CLDR <i>Language Plural Rules</i>. For these
+ * predefined rules, see the CLDR page at
+ * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
+ */
+
+/**
+ * Opaque UPluralRules object for use in C programs.
+ * @draft ICU 4.8
+ */
+struct UPluralRules;
+typedef struct UPluralRules UPluralRules; /**< C typedef for struct UPluralRules. @draft ICU 4.8 */
+
+/**
+ * Open a new UPluralRules object using the predefined plural rules for a
+ * given locale.
+ * @param locale The locale for which the rules are desired.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return A UPluralRules for the specified locale, or 0 if an error occurred.
+ * @draft ICU 4.8
+ */
+U_DRAFT UPluralRules* U_EXPORT2
+uplrules_open(const char *locale,
+ UErrorCode *status);
+
+/**
+ * Close a UPluralRules object. Once closed it may no longer be used.
+ * @param uplrules The UPluralRules object to close.
+ * @draft ICU 4.8
+ */
+U_DRAFT void U_EXPORT2
+uplrules_close(UPluralRules *uplrules);
+
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUPluralRulesPointer
+ * "Smart pointer" class, closes a UPluralRules via uplrules_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @draft ICU 4.8
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUPluralRulesPointer, UPluralRules, uplrules_close);
+
+U_NAMESPACE_END
+
+#endif
+
+
+/**
+ * Given a number, returns the keyword of the first rule that
+ * applies to the number, according to the supplied UPluralRules object.
+ * @param uplrules The UPluralRules object specifying the rules.
+ * @param number The number for which the rule has to be determined.
+ * @param keyword The keyword of the rule that applies to number.
+ * @param capacity The capacity of keyword.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return The length of keyword.
+ * @draft ICU 4.8
+ */
+U_DRAFT int32_t U_EXPORT2
+uplrules_select(const UPluralRules *uplrules,
+ double number,
+ UChar *keyword, int32_t capacity,
+ UErrorCode *status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uregex.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uregex.h
new file mode 100644
index 00000000000..a53f82fbb2f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uregex.h
@@ -0,0 +1,1605 @@
+/*
+**********************************************************************
+* Copyright (C) 2004-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* file name: uregex.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/utext.h"
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/localpointer.h"
+#include "unicode/parseerr.h"
+
+struct URegularExpression;
+/**
+ * Structure representing a compiled regular expression, 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,
+
+ /** If set, treat the entire pattern as a literal string.
+ * Metacharacters or escape sequences in the input sequence will be given
+ * no special meaning. Not implemented yet as of ICU 4.4.
+ *
+ * The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact
+ * on matching when used in conjunction with this flag.
+ * The other flags become superfluous.
+ * TODO: say which escapes are still handled; anything Java does
+ * early (\\u) we should still do.
+ * @stable ICU 4.0
+ */
+ UREGEX_LITERAL = 16,
+
+ /** 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,
+
+ /** Unix-only line endings.
+ * When this mode is enabled, only \\u000a is recognized as a line ending
+ * in the behavior of ., ^, and $.
+ * @stable ICU 4.0
+ */
+ UREGEX_UNIX_LINES = 1,
+
+ /** 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,
+
+ /** Error on Unrecognized backslash escapes.
+ * If set, fail with an error on patterns that contain
+ * backslash-escaped ASCII letters without a known special
+ * meaning. If this flag is not set, these
+ * escaped letters represent themselves.
+ * @stable ICU 4.0
+ */
+ UREGEX_ERROR_ON_UNKNOWN_ESCAPES = 512
+
+} 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 terminated.
+ * @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 numbers) 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. 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.
+ * <p>
+ * The contents of the pattern UText will be extracted and saved. Ownership of the
+ * UText struct itself remains with the caller. This is to match the behavior of
+ * uregex_open().
+ *
+ * @param pattern The Regular Expression pattern to be compiled.
+ * @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 numbers) 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.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT URegularExpression * U_EXPORT2
+uregex_openUText(UText *pattern,
+ 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 terminated.
+ * @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 numbers) 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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalURegularExpressionPointer
+ * "Smart pointer" class, closes a URegularExpression via uregex_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalURegularExpressionPointer, URegularExpression, uregex_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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 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);
+
+/**
+ * Returns a pointer to the source form of the pattern for this regular expression.
+ * This function will work even if the pattern was originally specified as a UText.
+ *
+ * @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);
+
+/**
+ * Returns the source text of the pattern for this regular expression.
+ * This function will work even if the pattern was originally specified as a UChar string.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status Receives errors detected by this function.
+ * @return the pattern text. The storage for the text is owned by the regular expression
+ * object, and must not be altered or deleted.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT UText * U_EXPORT2
+uregex_patternUText(const URegularExpression *regexp,
+ 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);
+
+
+/**
+ * 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; only a shallow clone 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.
+ *
+ * @param regexp The compiled regular expression.
+ * @param text The subject text string.
+ * @param status Receives errors detected by this function.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_setUText(URegularExpression *regexp,
+ UText *text,
+ UErrorCode *status);
+
+/**
+ * Get the subject text that is currently associated with this
+ * regular expression object. If the input was supplied using uregex_setText(),
+ * that pointer will be returned. Otherwise, the characters in the input will
+ * be extracted to a buffer and returned. In either case, ownership remains
+ * with the regular expression object.
+ *
+ * This function will work even if the input was originally specified as a UText.
+ *
+ * @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 Pointer 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);
+
+
+/**
+ * Get the subject text that is currently associated with this
+ * regular expression object.
+ *
+ * This function will work even if the input was originally specified as a UChar string.
+ *
+ * @param regexp The compiled regular expression.
+ * @param dest A mutable UText in which to store the current input.
+ * If NULL, a new UText will be created as an immutable shallow clone
+ * of the actual input string.
+ * @param status Receives errors detected by this function.
+ * @return The subject text currently associated with this regular expression.
+ * If a pre-allocated UText was provided, it will always be used and returned.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT UText * U_EXPORT2
+uregex_getUText(URegularExpression *regexp,
+ UText *dest,
+ UErrorCode *status);
+
+/**
+ * Set the subject text string upon which the regular expression is looking for matches
+ * without changing any other aspect of the matching state.
+ * The new and previous text strings must have the same content.
+ *
+ * This function is intended for use in environments where ICU is operating on
+ * strings that may move around in memory. It provides a mechanism for notifying
+ * ICU that the string has been relocated, and providing a new UText to access the
+ * string in its new position.
+ *
+ * Note that the regular expression implementation never copies the underlying text
+ * of a string being matched, but always operates directly on the original text
+ * provided by the user. Refreshing simply drops the references to the old text
+ * and replaces them with references to the new.
+ *
+ * Caution: this function is normally used only by very specialized
+ * system-level code. One example use case is with garbage collection
+ * that moves the text in memory.
+ *
+ * @param regexp The compiled regular expression.
+ * @param text The new (moved) text string.
+ * @param status Receives errors detected by this function.
+ *
+ * @draft ICU 4.8
+ */
+U_DRAFT void U_EXPORT2
+uregex_refreshUText(URegularExpression *regexp,
+ UText *text,
+ UErrorCode *status);
+
+/**
+ * Attempts to match the input string against the pattern.
+ * To succeed, the match must extend to the end of the string,
+ * or cover the complete match region.
+ *
+ * If startIndex >= zero the match operation starts at the specified
+ * index and must extend to the end of the input string. Any region
+ * that has been specified is reset.
+ *
+ * If startIndex == -1 the match must cover the input region, or the entire
+ * input string if no region has been set. This directly corresponds to
+ * Matcher.matches() in Java
+ *
+ * @param regexp The compiled regular expression.
+ * @param startIndex The input string (native) index at which to begin matching, or -1
+ * to match the input Region.
+ * @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);
+
+/**
+ * 64bit version of uregex_matches.
+ * Attempts to match the input string against the pattern.
+ * To succeed, the match must extend to the end of the string,
+ * or cover the complete match region.
+ *
+ * If startIndex >= zero the match operation starts at the specified
+ * index and must extend to the end of the input string. Any region
+ * that has been specified is reset.
+ *
+ * If startIndex == -1 the match must cover the input region, or the entire
+ * input string if no region has been set. This directly corresponds to
+ * Matcher.matches() in Java
+ *
+ * @param regexp The compiled regular expression.
+ * @param startIndex The input string (native) index at which to begin matching, or -1
+ * to match the input Region.
+ * @param status Receives errors detected by this function.
+ * @return TRUE if there is a match
+ * @draft ICU 4.6
+ */
+U_DRAFT UBool U_EXPORT2
+uregex_matches64(URegularExpression *regexp,
+ int64_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 startIndex is >= 0 any input region that was set for this
+ * URegularExpression is reset before the operation begins.
+ *
+ * <p>If the specified starting index == -1 the match begins at the start of the input
+ * region, or at the start of the full string if no region has been specified.
+ * This corresponds directly with Matcher.lookingAt() in Java.
+ *
+ * <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 (native) index at which to begin matching, or
+ * -1 to match the Input Region
+ * @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);
+
+/**
+ * 64bit version of uregex_lookingAt.
+ * 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 startIndex is >= 0 any input region that was set for this
+ * URegularExpression is reset before the operation begins.
+ *
+ * <p>If the specified starting index == -1 the match begins at the start of the input
+ * region, or at the start of the full string if no region has been specified.
+ * This corresponds directly with Matcher.lookingAt() in Java.
+ *
+ * <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 (native) index at which to begin matching, or
+ * -1 to match the Input Region
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if there is a match.
+ * @draft ICU 4.6
+ */
+U_DRAFT UBool U_EXPORT2
+uregex_lookingAt64(URegularExpression *regexp,
+ int64_t startIndex,
+ UErrorCode *status);
+
+/**
+ * Find the first matching substring of the input string that matches the pattern.
+ * If startIndex is >= zero the search for a match begins at the specified index,
+ * and any match region is reset. This corresponds directly with
+ * Matcher.find(startIndex) in Java.
+ *
+ * If startIndex == -1 the search begins at the start of the input region,
+ * or at the start of the full string if no region has been specified.
+ *
+ * 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 (native) in the input string to begin the search, or
+ * -1 to search within the Input Region.
+ * @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);
+
+/**
+ * 64bit version of uregex_find.
+ * Find the first matching substring of the input string that matches the pattern.
+ * If startIndex is >= zero the search for a match begins at the specified index,
+ * and any match region is reset. This corresponds directly with
+ * Matcher.find(startIndex) in Java.
+ *
+ * If startIndex == -1 the search begins at the start of the input region,
+ * or at the start of the full string if no region has been specified.
+ *
+ * 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 (native) in the input string to begin the search, or
+ * -1 to search within the Input Region.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if a match is found.
+ * @draft ICU 4.6
+ */
+U_DRAFT UBool U_EXPORT2
+uregex_find64(URegularExpression *regexp,
+ int64_t startIndex,
+ UErrorCode *status);
+
+/**
+ * Find the next pattern match in the input string. Begin searching
+ * the input at the location following the end of he previous match,
+ * or at the start of the string (or region) 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 a shallow immutable clone of the entire input string. The returned UText current native index
+ * is set to the beginning of the requested capture group. The capture group length is also
+ * returned via groupLength.
+ * 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 A mutable UText in which to store the current input.
+ * If NULL, a new UText will be created as an immutable shallow clone
+ * of the entire input string.
+ * @param groupLength The group length of the desired capture group.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The subject text currently associated with this regular expression.
+ * If a pre-allocated UText was provided, it will always be used and returned.
+
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT UText * U_EXPORT2
+uregex_groupUText(URegularExpression *regexp,
+ int32_t groupNum,
+ UText *dest,
+ int64_t *groupLength,
+ 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 Mutable UText to receive the matching string data.
+ * If NULL, a new UText will be created (which may not be mutable).
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The matching string data. If a pre-allocated UText was provided,
+ * it will always be used and returned.
+ *
+ * @internal ICU 4.4 technology preview
+ */
+U_INTERNAL UText * U_EXPORT2
+uregex_groupUTextDeep(URegularExpression *regexp,
+ int32_t groupNum,
+ UText *dest,
+ 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 (native) 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);
+
+/**
+ * 64bit version of uregex_start.
+ * 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 (native) position in the input of the text matched
+ * by the specified group.
+ * @draft ICU 4.6
+ */
+U_DRAFT int64_t U_EXPORT2
+uregex_start64(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 (native) 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);
+
+/**
+ * 64bit version of uregex_end.
+ * 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 (native) index of the position following the last matched character.
+ * @draft ICU 4.6
+ */
+U_DRAFT int64_t U_EXPORT2
+uregex_end64(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. Clears any
+ * match region that may have been set.
+ *
+ * @param regexp The compiled regular expression.
+ * @param index The position (native) 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);
+
+/**
+ * 64bit version of uregex_reset.
+ * 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. Clears any
+ * match region that may have been set.
+ *
+ * @param regexp The compiled regular expression.
+ * @param index The position (native) in the text at which a
+ * uregex_findNext() should begin searching.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_reset64(URegularExpression *regexp,
+ int64_t index,
+ UErrorCode *status);
+
+/**
+ * Sets the limits of the matching region for this URegularExpression.
+ * The region is the part of the input string that will be considered when matching.
+ * Invoking this method resets any saved state from the previous match,
+ * then sets the region to start at the index specified by the start parameter
+ * and end at the index specified by the end parameter.
+ *
+ * Depending on the transparency and anchoring being used (see useTransparentBounds
+ * and useAnchoringBounds), certain constructs such as anchors may behave differently
+ * at or around the boundaries of the region
+ *
+ * The function will fail if start is greater than limit, or if either index
+ * is less than zero or greater than the length of the string being matched.
+ *
+ * @param regexp The compiled regular expression.
+ * @param regionStart The (native) index to begin searches at.
+ * @param regionLimit The (native) index to end searches at (exclusive).
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+U_STABLE void U_EXPORT2
+uregex_setRegion(URegularExpression *regexp,
+ int32_t regionStart,
+ int32_t regionLimit,
+ UErrorCode *status);
+
+/**
+ * 64bit version of uregex_setRegion.
+ * Sets the limits of the matching region for this URegularExpression.
+ * The region is the part of the input string that will be considered when matching.
+ * Invoking this method resets any saved state from the previous match,
+ * then sets the region to start at the index specified by the start parameter
+ * and end at the index specified by the end parameter.
+ *
+ * Depending on the transparency and anchoring being used (see useTransparentBounds
+ * and useAnchoringBounds), certain constructs such as anchors may behave differently
+ * at or around the boundaries of the region
+ *
+ * The function will fail if start is greater than limit, or if either index
+ * is less than zero or greater than the length of the string being matched.
+ *
+ * @param regexp The compiled regular expression.
+ * @param regionStart The (native) index to begin searches at.
+ * @param regionLimit The (native) index to end searches at (exclusive).
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_setRegion64(URegularExpression *regexp,
+ int64_t regionStart,
+ int64_t regionLimit,
+ UErrorCode *status);
+
+/**
+ * Set the matching region and the starting index for subsequent matches
+ * in a single operation.
+ * This is useful because the usual function for setting the starting
+ * index, urgex_reset(), also resets any region limits.
+ *
+ * @param regexp The compiled regular expression.
+ * @param regionStart The (native) index to begin searches at.
+ * @param regionLimit The (native) index to end searches at (exclusive).
+ * @param startIndex The index in the input text at which the next
+ * match operation should begin.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_setRegionAndStart(URegularExpression *regexp,
+ int64_t regionStart,
+ int64_t regionLimit,
+ int64_t startIndex,
+ UErrorCode *status);
+
+/**
+ * Reports the start index of the matching region. Any matches found are limited to
+ * to the region bounded by regionStart (inclusive) and regionEnd (exclusive).
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return The starting (native) index of this matcher's region.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_regionStart(const URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * 64bit version of uregex_regionStart.
+ * Reports the start index of the matching region. Any matches found are limited to
+ * to the region bounded by regionStart (inclusive) and regionEnd (exclusive).
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return The starting (native) index of this matcher's region.
+ * @draft ICU 4.6
+ */
+U_DRAFT int64_t U_EXPORT2
+uregex_regionStart64(const URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * Reports the end index (exclusive) of the matching region for this URegularExpression.
+ * Any matches found are limited to to the region bounded by regionStart (inclusive)
+ * and regionEnd (exclusive).
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return The ending point (native) of this matcher's region.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_regionEnd(const URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * 64bit version of uregex_regionEnd.
+ * Reports the end index (exclusive) of the matching region for this URegularExpression.
+ * Any matches found are limited to to the region bounded by regionStart (inclusive)
+ * and regionEnd (exclusive).
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return The ending point (native) of this matcher's region.
+ * @draft ICU 4.6
+ */
+U_DRAFT int64_t U_EXPORT2
+uregex_regionEnd64(const URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * Queries the transparency of region bounds for this URegularExpression.
+ * See useTransparentBounds for a description of transparent and opaque bounds.
+ * By default, matching boundaries are opaque.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return TRUE if this matcher is using opaque bounds, false if it is not.
+ * @stable ICU 4.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_hasTransparentBounds(const URegularExpression *regexp,
+ UErrorCode *status);
+
+
+/**
+ * Sets the transparency of region bounds for this URegularExpression.
+ * Invoking this function with an argument of TRUE will set matches to use transparent bounds.
+ * If the boolean argument is FALSE, then opaque bounds will be used.
+ *
+ * Using transparent bounds, the boundaries of the matching region are transparent
+ * to lookahead, lookbehind, and boundary matching constructs. Those constructs can
+ * see text beyond the boundaries of the region while checking for a match.
+ *
+ * With opaque bounds, no text outside of the matching region is visible to lookahead,
+ * lookbehind, and boundary matching constructs.
+ *
+ * By default, opaque bounds are used.
+ *
+ * @param regexp The compiled regular expression.
+ * @param b TRUE for transparent bounds; FALSE for opaque bounds
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ **/
+U_STABLE void U_EXPORT2
+uregex_useTransparentBounds(URegularExpression *regexp,
+ UBool b,
+ UErrorCode *status);
+
+
+/**
+ * Return true if this URegularExpression is using anchoring bounds.
+ * By default, anchoring region bounds are used.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return TRUE if this matcher is using anchoring bounds.
+ * @stable ICU 4.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_hasAnchoringBounds(const URegularExpression *regexp,
+ UErrorCode *status);
+
+
+/**
+ * Set whether this URegularExpression is using Anchoring Bounds for its region.
+ * With anchoring bounds, pattern anchors such as ^ and $ will match at the start
+ * and end of the region. Without Anchoring Bounds, anchors will only match at
+ * the positions they would in the complete text.
+ *
+ * Anchoring Bounds are the default for regions.
+ *
+ * @param regexp The compiled regular expression.
+ * @param b TRUE if to enable anchoring bounds; FALSE to disable them.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+U_STABLE void U_EXPORT2
+uregex_useAnchoringBounds(URegularExpression *regexp,
+ UBool b,
+ UErrorCode *status);
+
+/**
+ * Return TRUE if the most recent matching operation touched the
+ * end of the text being processed. In this case, additional input text could
+ * change the results of that match.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return TRUE if the most recent match hit the end of input
+ * @stable ICU 4.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_hitEnd(const URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * Return TRUE the most recent match succeeded and additional input could cause
+ * it to fail. If this function returns false and a match was found, then more input
+ * might change the match but the match won't be lost. If a match was not found,
+ * then requireEnd has no meaning.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return TRUE if more input could cause the most recent match to no longer match.
+ * @stable ICU 4.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_requireEnd(const URegularExpression *regexp,
+ 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 destination 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 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 replacement A string containing the replacement text.
+ * @param dest A mutable UText that will receive the result.
+ * If NULL, a new UText will be created (which may not be mutable).
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A UText containing the results of the find and replace.
+ * If a pre-allocated UText was provided, it will always be used and returned.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT UText * U_EXPORT2
+uregex_replaceAllUText(URegularExpression *regexp,
+ UText *replacement,
+ UText *dest,
+ 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 destination 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);
+
+/**
+ * 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 replacement A string containing the replacement text.
+ * @param dest A mutable UText that will receive the result.
+ * If NULL, a new UText will be created (which may not be mutable).
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A UText containing the results of the find and replace.
+ * If a pre-allocated UText was provided, it will always be used and returned.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT UText * U_EXPORT2
+uregex_replaceFirstUText(URegularExpression *regexp,
+ UText *replacement,
+ UText *dest,
+ 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);
+
+
+/**
+ * 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>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 dest A mutable UText that will receive the result. Must not be NULL.
+ * @param status A reference to a UErrorCode to receive any errors.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_appendReplacementUText(URegularExpression *regexp,
+ UText *replacementText,
+ UText *dest,
+ 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);
+
+
+/**
+ * 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_appendTailUText()</code> is intended
+ * to be invoked after one or more invocations of the
+ * <code>uregex_appendReplacementUText()</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 dest A mutable UText that will receive the result. Must not be NULL.
+ *
+ * @param status Error code
+ *
+ * @return The destination UText.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT UText * U_EXPORT2
+uregex_appendTailUText(URegularExpression *regexp,
+ UText *dest,
+ 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.
+ *
+ * Each of the fields is copied from the input string to the destination
+ * buffer, and NUL terminated. The position of each field within
+ * the destination buffer is returned in the destFields array.
+ *
+ * If the delimiter pattern includes capture groups, the captured text will
+ * also appear in the destination array of output strings, interspersed
+ * with the fields. This is similar to Perl, but differs from Java,
+ * which ignores the presence of capture groups in the pattern.
+ *
+ * Trailing empty fields will always be returned, assuming sufficient
+ * destination capacity. This differs from the default behavior for Java
+ * and Perl where trailing empty fields are not returned.
+ *
+ * The number of strings produced by the split operation is returned.
+ * This count includes the strings from capture groups in the delimiter pattern.
+ * This behavior differs from Java, which ignores capture groups.
+ *
+ * @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);
+
+
+ /**
+ * 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>
+ * The behavior of this function is not very closely aligned with uregex_split();
+ * instead, it is based on (and implemented directly on top of) the C++ split method.
+ *
+ * @param regexp The compiled regular expression.
+ * @param destFields An array of mutable UText structs to receive the results of the split.
+ * If a field is NULL, a new UText is allocated to contain the results for
+ * that field. This new UText is not guaranteed to be mutable.
+ * @param destFieldsCapacity 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.
+ * 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.
+ *
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uregex_splitUText(URegularExpression *regexp,
+ UText *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status);
+
+
+
+
+/**
+ * Set a processing time limit for match operations with this URegularExpression.
+ *
+ * Some patterns, when matching certain strings, can run in exponential time.
+ * For practical purposes, the match operation may appear to be in an
+ * infinite loop.
+ * When a limit is set a match operation will fail with an error if the
+ * limit is exceeded.
+ * <p>
+ * The units of the limit are steps of the match engine.
+ * Correspondence with actual processor time will depend on the speed
+ * of the processor and the details of the specific pattern, but will
+ * typically be on the order of milliseconds.
+ * <p>
+ * By default, the matching time is not limited.
+ * <p>
+ *
+ * @param regexp The compiled regular expression.
+ * @param limit The limit value, or 0 for no limit.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+U_STABLE void U_EXPORT2
+uregex_setTimeLimit(URegularExpression *regexp,
+ int32_t limit,
+ UErrorCode *status);
+
+/**
+ * Get the time limit for for matches with this URegularExpression.
+ * A return value of zero indicates that there is no limit.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return the maximum allowed time for a match, in units of processing steps.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_getTimeLimit(const URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * Set the amount of heap storage available for use by the match backtracking stack.
+ * <p>
+ * ICU uses a backtracking regular expression engine, with the backtrack stack
+ * maintained on the heap. This function sets the limit to the amount of memory
+ * that can be used for this purpose. A backtracking stack overflow will
+ * result in an error from the match operation that caused it.
+ * <p>
+ * A limit is desirable because a malicious or poorly designed pattern can use
+ * excessive memory, potentially crashing the process. A limit is enabled
+ * by default.
+ * <p>
+ * @param regexp The compiled regular expression.
+ * @param limit The maximum size, in bytes, of the matching backtrack stack.
+ * A value of -1 means no limit.
+ * The limit must be greater than zero, or -1.
+ * @param status A reference to a UErrorCode to receive any errors.
+ *
+ * @stable ICU 4.0
+ */
+U_STABLE void U_EXPORT2
+uregex_setStackLimit(URegularExpression *regexp,
+ int32_t limit,
+ UErrorCode *status);
+
+/**
+ * Get the size of the heap storage available for use by the back tracking stack.
+ *
+ * @return the maximum backtracking stack size, in bytes, or zero if the
+ * stack size is unlimited.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_getStackLimit(const URegularExpression *regexp,
+ UErrorCode *status);
+
+
+/**
+ * Function pointer for a regular expression matching callback function.
+ * When set, a callback function will be called periodically during matching
+ * operations. If the call back function returns FALSE, the matching
+ * operation will be terminated early.
+ *
+ * Note: the callback function must not call other functions on this
+ * URegularExpression.
+ *
+ * @param context context pointer. The callback function will be invoked
+ * with the context specified at the time that
+ * uregex_setMatchCallback() is called.
+ * @param steps the accumulated processing time, in match steps,
+ * for this matching operation.
+ * @return TRUE to continue the matching operation.
+ * FALSE to terminate the matching operation.
+ * @stable ICU 4.0
+ */
+U_CDECL_BEGIN
+typedef UBool U_CALLCONV URegexMatchCallback (
+ const void *context,
+ int32_t steps);
+U_CDECL_END
+
+/**
+ * Set a callback function for this URegularExpression.
+ * During matching operations the function will be called periodically,
+ * giving the application the opportunity to terminate a long-running
+ * match.
+ *
+ * @param regexp The compiled regular expression.
+ * @param callback A pointer to the user-supplied callback function.
+ * @param context User context pointer. The value supplied at the
+ * time the callback function is set will be saved
+ * and passed to the callback each time that it is called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+U_STABLE void U_EXPORT2
+uregex_setMatchCallback(URegularExpression *regexp,
+ URegexMatchCallback *callback,
+ const void *context,
+ UErrorCode *status);
+
+
+/**
+ * Get the callback function for this URegularExpression.
+ *
+ * @param regexp The compiled regular expression.
+ * @param callback Out parameter, receives a pointer to the user-supplied
+ * callback function.
+ * @param context Out parameter, receives the user context pointer that
+ * was set when uregex_setMatchCallback() was called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 4.0
+ */
+U_STABLE void U_EXPORT2
+uregex_getMatchCallback(const URegularExpression *regexp,
+ URegexMatchCallback **callback,
+ const void **context,
+ UErrorCode *status);
+
+
+/**
+ * Function pointer for a regular expression find callback function.
+ *
+ * When set, a callback function will be called during a find operation
+ * and for operations that depend on find, such as findNext, split and some replace
+ * operations like replaceFirst.
+ * The callback will usually be called after each attempt at a match, but this is not a
+ * guarantee that the callback will be invoked at each character. For finds where the
+ * match engine is invoked at each character, this may be close to true, but less likely
+ * for more optimized loops where the pattern is known to only start, and the match
+ * engine invoked, at certain characters.
+ * When invoked, this callback will specify the index at which a match operation is about
+ * to be attempted, giving the application the opportunity to terminate a long-running
+ * find operation.
+ *
+ * If the call back function returns FALSE, the find operation will be terminated early.
+ *
+ * Note: the callback function must not call other functions on this
+ * URegularExpression
+ *
+ * @param context context pointer. The callback function will be invoked
+ * with the context specified at the time that
+ * uregex_setFindProgressCallback() is called.
+ * @param matchIndex the next index at which a match attempt will be attempted for this
+ * find operation. If this callback interrupts the search, this is the
+ * index at which a find/findNext operation may be re-initiated.
+ * @return TRUE to continue the matching operation.
+ * FALSE to terminate the matching operation.
+ * @draft ICU 4.6
+ */
+U_CDECL_BEGIN
+typedef UBool U_CALLCONV URegexFindProgressCallback (
+ const void *context,
+ int64_t matchIndex);
+U_CDECL_END
+
+/**
+ * Set the find progress callback function for this URegularExpression.
+ *
+ * @param regexp The compiled regular expression.
+ * @param callback A pointer to the user-supplied callback function.
+ * @param context User context pointer. The value supplied at the
+ * time the callback function is set will be saved
+ * and passed to the callback each time that it is called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_setFindProgressCallback(URegularExpression *regexp,
+ URegexFindProgressCallback *callback,
+ const void *context,
+ UErrorCode *status);
+
+
+/**
+ * Get the find progress callback function for this URegularExpression.
+ *
+ * @param regexp The compiled regular expression.
+ * @param callback Out parameter, receives a pointer to the user-supplied
+ * callback function.
+ * @param context Out parameter, receives the user context pointer that
+ * was set when uregex_setFindProgressCallback() was called.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_getFindProgressCallback(const URegularExpression *regexp,
+ URegexFindProgressCallback **callback,
+ const void **context,
+ UErrorCode *status);
+
+#endif /* !UCONFIG_NO_REGULAR_EXPRESSIONS */
+#endif /* UREGEX_H */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/usearch.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/usearch.h
new file mode 100644
index 00000000000..5c418a558b4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/usearch.h
@@ -0,0 +1,834 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2011 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 && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/localpointer.h"
+#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,
+ /**
+ * Option to control how collation elements are compared.
+ * The default value will be USEARCH_STANDARD_ELEMENT_COMPARISON.
+ * @stable ICU 4.4
+ */
+ USEARCH_ELEMENT_COMPARISON,
+
+ 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,
+ /**
+ * Value (default) for USEARCH_ELEMENT_COMPARISON;
+ * standard collation element comparison at the specified collator
+ * strength.
+ * @stable ICU 4.4
+ */
+ USEARCH_STANDARD_ELEMENT_COMPARISON,
+ /**
+ * Value for USEARCH_ELEMENT_COMPARISON;
+ * collation element comparison is modified to effectively provide
+ * behavior between the specified strength and strength - 1. Collation
+ * elements in the pattern that have the base weight for the specified
+ * strength are treated as "wildcards" that match an element with any
+ * other weight at that collation level in the searched text. For
+ * example, with a secondary-strength English collator, a plain 'e' in
+ * the pattern will match a plain e or an e with any diacritic in the
+ * searched text, but an e with diacritic in the pattern will only
+ * match an e with the same diacritic in the searched text.
+ * @stable ICU 4.4
+ */
+ USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD,
+ /**
+ * Value for USEARCH_ELEMENT_COMPARISON.
+ * collation element comparison is modified to effectively provide
+ * behavior between the specified strength and strength - 1. Collation
+ * elements in either the pattern or the searched text that have the
+ * base weight for the specified strength are treated as "wildcards"
+ * that match an element with any other weight at that collation level.
+ * For example, with a secondary-strength English collator, a plain 'e'
+ * in the pattern will match a plain e or an e with any diacritic in the
+ * searched text, but an e with diacritic in the pattern will only
+ * match an e with the same diacritic or a plain e in the searched text.
+ * @stable ICU 4.4
+ */
+ USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD,
+
+ 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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUStringSearchPointer
+ * "Smart pointer" class, closes a UStringSearch via usearch_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUStringSearchPointer, UStringSearch, usearch_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/* 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 equal or 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.
+* <p>
+* When <tt>USEARCH_OVERLAP</tt> option is off, the last index of the
+* result match is always less than <tt>position</tt>.
+* When <tt>USERARCH_OVERLAP</tt> is on, the result match may span across
+* <tt>position</tt>.
+* @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);
+
+/**
+ * Simple forward search for the pattern, starting at a specified index,
+ * and using using a default set search options.
+ *
+ * This is an experimental function, and is not an official part of the
+ * ICU API.
+ *
+ * The collator options, such as UCOL_STRENGTH and UCOL_NORMALIZTION, are honored.
+ *
+ * The UStringSearch options USEARCH_CANONICAL_MATCH, USEARCH_OVERLAP and
+ * any Break Iterator are ignored.
+ *
+ * Matches obey the following constraints:
+ *
+ * Characters at the start or end positions of a match that are ignorable
+ * for collation are not included as part of the match, unless they
+ * are part of a combining sequence, as described below.
+ *
+ * A match will not include a partial combining sequence. Combining
+ * character sequences are considered to be inseperable units,
+ * and either match the pattern completely, or are considered to not match
+ * at all. Thus, for example, an A followed a combining accent mark will
+ * not be found when searching for a plain (unaccented) A. (unless
+ * the collation strength has been set to ignore all accents).
+ *
+ * When beginning a search, the initial starting position, startIdx,
+ * is assumed to be an acceptable match boundary with respect to
+ * combining characters. A combining sequence that spans across the
+ * starting point will not supress a match beginning at startIdx.
+ *
+ * Characters that expand to multiple collation elements
+ * (German sharp-S becoming 'ss', or the composed forms of accented
+ * characters, for example) also must match completely.
+ * Searching for a single 's' in a string containing only a sharp-s will
+ * find no match.
+ *
+ *
+ * @param strsrch the UStringSearch struct, which references both
+ * the text to be searched and the pattern being sought.
+ * @param startIdx The index into the text to begin the search.
+ * @param matchStart An out parameter, the starting index of the matched text.
+ * This parameter may be NULL.
+ * A value of -1 will be returned if no match was found.
+ * @param matchLimit Out parameter, the index of the first position following the matched text.
+ * The matchLimit will be at a suitable position for beginning a subsequent search
+ * in the input text.
+ * This parameter may be NULL.
+ * A value of -1 will be returned if no match was found.
+ *
+ * @param status Report any errors. Note that no match found is not an error.
+ * @return TRUE if a match was found, FALSE otherwise.
+ *
+ * @internal
+ */
+U_INTERNAL UBool U_EXPORT2 usearch_search(UStringSearch *strsrch,
+ int32_t startIdx,
+ int32_t *matchStart,
+ int32_t *matchLimit,
+ UErrorCode *status);
+
+/**
+ * Simple backwards search for the pattern, starting at a specified index,
+ * and using using a default set search options.
+ *
+ * This is an experimental function, and is not an official part of the
+ * ICU API.
+ *
+ * The collator options, such as UCOL_STRENGTH and UCOL_NORMALIZTION, are honored.
+ *
+ * The UStringSearch options USEARCH_CANONICAL_MATCH, USEARCH_OVERLAP and
+ * any Break Iterator are ignored.
+ *
+ * Matches obey the following constraints:
+ *
+ * Characters at the start or end positions of a match that are ignorable
+ * for collation are not included as part of the match, unless they
+ * are part of a combining sequence, as described below.
+ *
+ * A match will not include a partial combining sequence. Combining
+ * character sequences are considered to be inseperable units,
+ * and either match the pattern completely, or are considered to not match
+ * at all. Thus, for example, an A followed a combining accent mark will
+ * not be found when searching for a plain (unaccented) A. (unless
+ * the collation strength has been set to ignore all accents).
+ *
+ * When beginning a search, the initial starting position, startIdx,
+ * is assumed to be an acceptable match boundary with respect to
+ * combining characters. A combining sequence that spans across the
+ * starting point will not supress a match beginning at startIdx.
+ *
+ * Characters that expand to multiple collation elements
+ * (German sharp-S becoming 'ss', or the composed forms of accented
+ * characters, for example) also must match completely.
+ * Searching for a single 's' in a string containing only a sharp-s will
+ * find no match.
+ *
+ *
+ * @param strsrch the UStringSearch struct, which references both
+ * the text to be searched and the pattern being sought.
+ * @param startIdx The index into the text to begin the search.
+ * @param matchStart An out parameter, the starting index of the matched text.
+ * This parameter may be NULL.
+ * A value of -1 will be returned if no match was found.
+ * @param matchLimit Out parameter, the index of the first position following the matched text.
+ * The matchLimit will be at a suitable position for beginning a subsequent search
+ * in the input text.
+ * This parameter may be NULL.
+ * A value of -1 will be returned if no match was found.
+ *
+ * @param status Report any errors. Note that no match found is not an error.
+ * @return TRUE if a match was found, FALSE otherwise.
+ *
+ * @internal
+ */
+U_INTERNAL UBool U_EXPORT2 usearch_searchBackwards(UStringSearch *strsrch,
+ int32_t startIdx,
+ int32_t *matchStart,
+ int32_t *matchLimit,
+ UErrorCode *status);
+
+#endif /* #if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uspoof.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uspoof.h
new file mode 100644
index 00000000000..7a218ca934b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/uspoof.h
@@ -0,0 +1,887 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2010, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+* file name: uspoof.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2008Feb13
+* created by: Andy Heninger
+*
+* Unicode Spoof Detection
+*/
+
+#ifndef USPOOF_H
+#define USPOOF_H
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "unicode/parseerr.h"
+#include "unicode/localpointer.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+#if U_SHOW_CPLUSPLUS_API
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_USE
+#endif
+
+
+/**
+ * \file
+ * \brief Unicode Security and Spoofing Detection, C API.
+ *
+ * These functions are intended to check strings, typically
+ * identifiers of some type, such as URLs, for the presence of
+ * characters that are likely to be visually confusing -
+ * for cases where the displayed form of an identifier may
+ * not be what it appears to be.
+ *
+ * Unicode Technical Report #36, http://unicode.org/reports/tr36, and
+ * Unicode Technical Standard #39, http://unicode.org/reports/tr39
+ * "Unicode security considerations", give more background on
+ * security an spoofing issues with Unicode identifiers.
+ * The tests and checks provided by this module implement the recommendations
+ * from those Unicode documents.
+ *
+ * The tests available on identifiers fall into two general categories:
+ * -# Single identifier tests. Check whether an identifier is
+ * potentially confusable with any other string, or is suspicious
+ * for other reasons.
+ * -# Two identifier tests. Check whether two specific identifiers are confusable.
+ * This does not consider whether either of strings is potentially
+ * confusable with any string other than the exact one specified.
+ *
+ * The steps to perform confusability testing are
+ * -# Open a USpoofChecker.
+ * -# Configure the USPoofChecker for the desired set of tests. The tests that will
+ * be performed are specified by a set of USpoofChecks flags.
+ * -# Perform the checks using the pre-configured USpoofChecker. The results indicate
+ * which (if any) of the selected tests have identified possible problems with the identifier.
+ * Results are reported as a set of USpoofChecks flags; this mirrors the form in which
+ * the set of tests to perform was originally specified to the USpoofChecker.
+ *
+ * A USpoofChecker may be used repeatedly to perform checks on any number of identifiers.
+ *
+ * Thread Safety: The test functions for checking a single identifier, or for testing
+ * whether two identifiers are possible confusable, are thread safe.
+ * They may called concurrently, from multiple threads, using the same USpoofChecker instance.
+ *
+ * More generally, the standard ICU thread safety rules apply: functions that take a
+ * const USpoofChecker parameter are thread safe. Those that take a non-const
+ * USpoofChecier are not thread safe.
+ *
+ *
+ * Descriptions of the available checks.
+ *
+ * When testing whether pairs of identifiers are confusable, with the uspoof_areConfusable()
+ * family of functions, the relevant tests are
+ *
+ * -# USPOOF_SINGLE_SCRIPT_CONFUSABLE: All of the characters from the two identifiers are
+ * from a single script, and the two identifiers are visually confusable.
+ * -# USPOOF_MIXED_SCRIPT_CONFUSABLE: At least one of the identifiers contains characters
+ * from more than one script, and the two identifiers are visually confusable.
+ * -# USPOOF_WHOLE_SCRIPT_CONFUSABLE: Each of the two identifiers is of a single script, but
+ * the two identifiers are from different scripts, and they are visually confusable.
+ *
+ * The safest approach is to enable all three of these checks as a group.
+ *
+ * USPOOF_ANY_CASE is a modifier for the above tests. If the identifiers being checked can
+ * be of mixed case and are used in a case-sensitive manner, this option should be specified.
+ *
+ * If the identifiers being checked are used in a case-insensitive manner, and if they are
+ * displayed to users in lower-case form only, the USPOOF_ANY_CASE option should not be
+ * specified. Confusabality issues involving upper case letters will not be reported.
+ *
+ * When performing tests on a single identifier, with the uspoof_check() family of functions,
+ * the relevant tests are:
+ *
+ * -# USPOOF_MIXED_SCRIPT_CONFUSABLE: the identifier contains characters from multiple
+ * scripts, and there exists an identifier of a single script that is visually confusable.
+ * -# USPOOF_WHOLE_SCRIPT_CONFUSABLE: the identifier consists of characters from a single
+ * script, and there exists a visually confusable identifier.
+ * The visually confusable identifier also consists of characters from a single script.
+ * but not the same script as the identifier being checked.
+ * -# USPOOF_ANY_CASE: modifies the mixed script and whole script confusables tests. If
+ * specified, the checks will consider confusable characters of any case. If this flag is not
+ * set, the test is performed assuming case folded identifiers.
+ * -# USPOOF_SINGLE_SCRIPT: check that the identifier contains only characters from a
+ * single script. (Characters from the 'common' and 'inherited' scripts are ignored.)
+ * This is not a test for confusable identifiers
+ * -# USPOOF_INVISIBLE: check an identifier for the presence of invisible characters,
+ * such as zero-width spaces, or character sequences that are
+ * likely not to display, such as multiple occurrences of the same
+ * non-spacing mark. This check does not test the input string as a whole
+ * for conformance to any particular syntax for identifiers.
+ * -# USPOOF_CHAR_LIMIT: check that an identifier contains only characters from a specified set
+ * of acceptable characters. See uspoof_setAllowedChars() and
+ * uspoof_setAllowedLocales().
+ *
+ * Note on Scripts:
+ * Characters from the Unicode Scripts "Common" and "Inherited" are ignored when considering
+ * the script of an identifier. Common characters include digits and symbols that
+ * are normally used with text from more than one script.
+ *
+ * Identifier Skeletons: A skeleton is a transformation of an identifier, such that
+ * all identifiers that are confusable with each other have the same skeleton.
+ * Using skeletons, it is possible to build a dictionary data structure for
+ * a set of identifiers, and then quickly test whether a new identifier is
+ * confusable with an identifier already in the set. The uspoof_getSkeleton()
+ * family of functions will produce the skeleton from an identifier.
+ *
+ * Note that skeletons are not guaranteed to be stable between versions
+ * of Unicode or ICU, so an applications should not rely on creating a permanent,
+ * or difficult to update, database of skeletons. Instabilities result from
+ * identifying new pairs or sequences of characters that are visually
+ * confusable, and thus must be mapped to the same skeleton character(s).
+ *
+ */
+
+struct USpoofChecker;
+typedef struct USpoofChecker USpoofChecker; /**< typedef for C of USpoofChecker */
+
+/**
+ * Enum for the kinds of checks that USpoofChecker can perform.
+ * These enum values are used both to select the set of checks that
+ * will be performed, and to report results from the check function.
+ *
+ * @stable ICU 4.2
+ */
+typedef enum USpoofChecks {
+ /** Single script confusable test.
+ * When testing whether two identifiers are confusable, report that they are if
+ * both are from the same script and they are visually confusable.
+ * Note: this test is not applicable to a check of a single identifier.
+ */
+ USPOOF_SINGLE_SCRIPT_CONFUSABLE = 1,
+
+ /** Mixed script confusable test.
+ * When checking a single identifier, report a problem if
+ * the identifier contains multiple scripts, and
+ * is confusable with some other identifier in a single script
+ * When testing whether two identifiers are confusable, report that they are if
+ * the two IDs are visually confusable,
+ * and at least one contains characters from more than one script.
+ */
+ USPOOF_MIXED_SCRIPT_CONFUSABLE = 2,
+
+ /** Whole script confusable test.
+ * When checking a single identifier, report a problem if
+ * The identifier is of a single script, and
+ * there exists a confusable identifier in another script.
+ * When testing whether two identifiers are confusable, report that they are if
+ * each is of a single script,
+ * the scripts of the two identifiers are different, and
+ * the identifiers are visually confusable.
+ */
+ USPOOF_WHOLE_SCRIPT_CONFUSABLE = 4,
+
+ /** Any Case Modifier for confusable identifier tests.
+ If specified, consider all characters, of any case, when looking for confusables.
+ If USPOOF_ANY_CASE is not specified, identifiers being checked are assumed to have been
+ case folded. Upper case confusable characters will not be checked.
+ Selects between Lower Case Confusable and
+ Any Case Confusable. */
+ USPOOF_ANY_CASE = 8,
+
+ /** Check that an identifier contains only characters from a
+ * single script (plus chars from the common and inherited scripts.)
+ * Applies to checks of a single identifier check only.
+ */
+ USPOOF_SINGLE_SCRIPT = 16,
+
+ /** Check an identifier for the presence of invisible characters,
+ * such as zero-width spaces, or character sequences that are
+ * likely not to display, such as multiple occurrences of the same
+ * non-spacing mark. This check does not test the input string as a whole
+ * for conformance to any particular syntax for identifiers.
+ */
+ USPOOF_INVISIBLE = 32,
+
+ /** Check that an identifier contains only characters from a specified set
+ * of acceptable characters. See uspoof_setAllowedChars() and
+ * uspoof_setAllowedLocales().
+ */
+ USPOOF_CHAR_LIMIT = 64,
+
+ USPOOF_ALL_CHECKS = 0x7f
+ } USpoofChecks;
+
+
+/**
+ * Create a Unicode Spoof Checker, configured to perform all
+ * checks except for USPOOF_LOCALE_LIMIT and USPOOF_CHAR_LIMIT.
+ * Note that additional checks may be added in the future,
+ * resulting in the changes to the default checking behavior.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @return the newly created Spoof Checker
+ * @stable ICU 4.2
+ */
+U_STABLE USpoofChecker * U_EXPORT2
+uspoof_open(UErrorCode *status);
+
+
+/**
+ * Open a Spoof checker from its serialized from, stored in 32-bit-aligned memory.
+ * Inverse of uspoof_serialize().
+ * The memory containing the serialized data must remain valid and unchanged
+ * as long as the spoof checker, or any cloned copies of the spoof checker,
+ * are in use. Ownership of the memory remains with the caller.
+ * The spoof checker (and any clones) must be closed prior to deleting the
+ * serialized data.
+ *
+ * @param data a pointer to 32-bit-aligned memory containing the serialized form of spoof data
+ * @param length the number of bytes available at data;
+ * can be more than necessary
+ * @param pActualLength receives the actual number of bytes at data taken up by the data;
+ * can be NULL
+ * @param pErrorCode ICU error code
+ * @return the spoof checker.
+ *
+ * @see uspoof_open
+ * @see uspoof_serialize
+ * @stable ICU 4.2
+ */
+U_STABLE USpoofChecker * U_EXPORT2
+uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLength,
+ UErrorCode *pErrorCode);
+
+/**
+ * Open a Spoof Checker from the source form of the spoof data.
+ * The Three inputs correspond to the Unicode data files confusables.txt
+ * confusablesWholeScript.txt and xidmdifications.txt as described in
+ * Unicode UAX 39. The syntax of the source data is as described in UAX 39 for
+ * these files, and the content of these files is acceptable input.
+ *
+ * The character encoding of the (char *) input text is UTF-8.
+ *
+ * @param confusables a pointer to the confusable characters definitions,
+ * as found in file confusables.txt from unicode.org.
+ * @param confusablesLen The length of the confusables text, or -1 if the
+ * input string is zero terminated.
+ * @param confusablesWholeScript
+ * a pointer to the whole script confusables definitions,
+ * as found in the file confusablesWholeScript.txt from unicode.org.
+ * @param confusablesWholeScriptLen The length of the whole script confusables text, or
+ * -1 if the input string is zero terminated.
+ * @param errType In the event of an error in the input, indicates
+ * which of the input files contains the error.
+ * The value is one of USPOOF_SINGLE_SCRIPT_CONFUSABLE or
+ * USPOOF_WHOLE_SCRIPT_CONFUSABLE, or
+ * zero if no errors are found.
+ * @param pe In the event of an error in the input, receives the position
+ * in the input text (line, offset) of the error.
+ * @param status an in/out ICU UErrorCode. Among the possible errors is
+ * U_PARSE_ERROR, which is used to report syntax errors
+ * in the input.
+ * @return A spoof checker that uses the rules from the input files.
+ * @stable ICU 4.2
+ */
+U_STABLE USpoofChecker * U_EXPORT2
+uspoof_openFromSource(const char *confusables, int32_t confusablesLen,
+ const char *confusablesWholeScript, int32_t confusablesWholeScriptLen,
+ int32_t *errType, UParseError *pe, UErrorCode *status);
+
+
+/**
+ * Close a Spoof Checker, freeing any memory that was being held by
+ * its implementation.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+uspoof_close(USpoofChecker *sc);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUSpoofCheckerPointer
+ * "Smart pointer" class, closes a USpoofChecker via uspoof_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckerPointer, USpoofChecker, uspoof_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Clone a Spoof Checker. The clone will be set to perform the same checks
+ * as the original source.
+ *
+ * @param sc The source USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return
+ * @stable ICU 4.2
+ */
+U_STABLE USpoofChecker * U_EXPORT2
+uspoof_clone(const USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Specify the set of checks that will be performed by the check
+ * functions of this Spoof Checker.
+ *
+ * @param sc The USpoofChecker
+ * @param checks The set of checks that this spoof checker will perform.
+ * The value is a bit set, obtained by OR-ing together
+ * values from enum USpoofChecks.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ *
+ */
+U_STABLE void U_EXPORT2
+uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status);
+
+/**
+ * Get the set of checks that this Spoof Checker has been configured to perform.
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return The set of checks that this spoof checker will perform.
+ * The value is a bit set, obtained by OR-ing together
+ * values from enum USpoofChecks.
+ * @stable ICU 4.2
+ *
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_getChecks(const USpoofChecker *sc, UErrorCode *status);
+
+/**
+ * Limit characters that are acceptable in identifiers being checked to those
+ * normally used with the languages associated with the specified locales.
+ * Any previously specified list of locales is replaced by the new settings.
+ *
+ * A set of languages is determined from the locale(s), and
+ * from those a set of acceptable Unicode scripts is determined.
+ * Characters from this set of scripts, along with characters from
+ * the "common" and "inherited" Unicode Script categories
+ * will be permitted.
+ *
+ * Supplying an empty string removes all restrictions;
+ * characters from any script will be allowed.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USpoofChecker when calling this function with a non-empty list
+ * of locales.
+ *
+ * The Unicode Set of characters that will be allowed is accessible
+ * via the uspoof_getAllowedChars() function. uspoof_setAllowedLocales()
+ * will <i>replace</i> any previously applied set of allowed characters.
+ *
+ * Adjustments, such as additions or deletions of certain classes of characters,
+ * can be made to the result of uspoof_setAllowedLocales() by
+ * fetching the resulting set with uspoof_getAllowedChars(),
+ * manipulating it with the Unicode Set API, then resetting the
+ * spoof detectors limits with uspoof_setAllowedChars()
+ *
+ * @param sc The USpoofChecker
+ * @param localesList A list list of locales, from which the language
+ * and associated script are extracted. The locales
+ * are comma-separated if there is more than one.
+ * White space may not appear within an individual locale,
+ * but is ignored otherwise.
+ * The locales are syntactically like those from the
+ * HTTP Accept-Language header.
+ * If the localesList is empty, no restrictions will be placed on
+ * the allowed characters.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status);
+
+/**
+ * Get a list of locales for the scripts that are acceptable in strings
+ * to be checked. If no limitations on scripts have been specified,
+ * an empty string will be returned.
+ *
+ * uspoof_setAllowedChars() will reset the list of allowed to be empty.
+ *
+ * The format of the returned list is the same as that supplied to
+ * uspoof_setAllowedLocales(), but returned list may not be identical
+ * to the originally specified string; the string may be reformatted,
+ * and information other than languages from
+ * the originally specified locales may be omitted.
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A string containing a list of locales corresponding
+ * to the acceptable scripts, formatted like an
+ * HTTP Accept Language value.
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE const char * U_EXPORT2
+uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Limit the acceptable characters to those specified by a Unicode Set.
+ * Any previously specified character limit is
+ * is replaced by the new settings. This includes limits on
+ * characters that were set with the uspoof_setAllowedLocales() function.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USpoofChecker by this function.
+ *
+ * @param sc The USpoofChecker
+ * @param chars A Unicode Set containing the list of
+ * characters that are permitted. Ownership of the set
+ * remains with the caller. The incoming set is cloned by
+ * this function, so there are no restrictions on modifying
+ * or deleting the USet after calling this function.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status);
+
+
+/**
+ * Get a USet for the characters permitted in an identifier.
+ * This corresponds to the limits imposed by the Set Allowed Characters
+ * functions. Limitations imposed by other checks will not be
+ * reflected in the set returned by this function.
+ *
+ * The returned set will be frozen, meaning that it cannot be modified
+ * by the caller.
+ *
+ * Ownership of the returned set remains with the Spoof Detector. The
+ * returned set will become invalid if the spoof detector is closed,
+ * or if a new set of allowed characters is specified.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A USet containing the characters that are permitted by
+ * the USPOOF_CHAR_LIMIT test.
+ * @stable ICU 4.2
+ */
+U_STABLE const USet * U_EXPORT2
+uspoof_getAllowedChars(const USpoofChecker *sc, UErrorCode *status);
+
+
+#if U_SHOW_CPLUSPLUS_API
+/**
+ * Limit the acceptable characters to those specified by a Unicode Set.
+ * Any previously specified character limit is
+ * is replaced by the new settings. This includes limits on
+ * characters that were set with the uspoof_setAllowedLocales() function.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USoofChecker by this function.
+ *
+ * @param sc The USpoofChecker
+ * @param chars A Unicode Set containing the list of
+ * characters that are permitted. Ownership of the set
+ * remains with the caller. The incoming set is cloned by
+ * this function, so there are no restrictions on modifying
+ * or deleting the USet after calling this function.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const UnicodeSet *chars, UErrorCode *status);
+
+
+/**
+ * Get a UnicodeSet for the characters permitted in an identifier.
+ * This corresponds to the limits imposed by the Set Allowed Characters /
+ * UnicodeSet functions. Limitations imposed by other checks will not be
+ * reflected in the set returned by this function.
+ *
+ * The returned set will be frozen, meaning that it cannot be modified
+ * by the caller.
+ *
+ * Ownership of the returned set remains with the Spoof Detector. The
+ * returned set will become invalid if the spoof detector is closed,
+ * or if a new set of allowed characters is specified.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A UnicodeSet containing the characters that are permitted by
+ * the USPOOF_CHAR_LIMIT test.
+ * @stable ICU 4.2
+ */
+U_STABLE const UnicodeSet * U_EXPORT2
+uspoof_getAllowedUnicodeSet(const USpoofChecker *sc, UErrorCode *status);
+#endif
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param text The string to be checked for possible security issues,
+ * in UTF-16 format.
+ * @param length the length of the string to be checked, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * zero terminated.
+ * @param position An out parameter that receives the index of the
+ * first string position that fails the allowed character
+ * limitation checks.
+ * This parameter may be null if the position information
+ * is not needed.
+ * If the string passes the requested checks the
+ * parameter value will not be set.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. Zero is returned if no issues
+ * are found with the input string.
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_check(const USpoofChecker *sc,
+ const UChar *text, int32_t length,
+ int32_t *position,
+ UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param text A UTF-8 string to be checked for possible security issues.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param position An out parameter that receives the index of the
+ * first string position that fails the allowed character
+ * limitation checks.
+ * This parameter may be null if the position information
+ * is not needed.
+ * If the string passes the requested checks the
+ * parameter value will not be set.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * If the input contains invalid UTF-8 sequences,
+ * a status of U_INVALID_CHAR_FOUND will be returned.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. Zero is returned if no issues
+ * are found with the input string.
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+ const char *text, int32_t length,
+ int32_t *position,
+ UErrorCode *status);
+
+
+#if U_SHOW_CPLUSPLUS_API
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param text A UnicodeString to be checked for possible security issues.
+ * @position An out parameter that receives the index of the
+ * first string position that fails the allowed character
+ * limitation checks.
+ * This parameter may be null if the position information
+ * is not needed.
+ * If the string passes the requested checks the
+ * parameter value will not be set.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. Zero is returned if no issues
+ * are found with the input string.
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+ const U_NAMESPACE_QUALIFIER UnicodeString &text,
+ int32_t *position,
+ UErrorCode *status);
+
+#endif
+
+
+/**
+ * Check the whether two specified strings are visually confusable.
+ * The types of confusability to be tested - single script, mixed script,
+ * or whole script - are determined by the check options set for the
+ * USpoofChecker.
+ *
+ * The tests to be performed are controlled by the flags
+ * USPOOF_SINGLE_SCRIPT_CONFUSABLE
+ * USPOOF_MIXED_SCRIPT_CONFUSABLE
+ * USPOOF_WHOLE_SCRIPT_CONFUSABLE
+ * At least one of these tests must be selected.
+ *
+ * USPOOF_ANY_CASE is a modifier for the tests. Select it if the identifiers
+ * may be of mixed case.
+ * If identifiers are case folded for comparison and
+ * display to the user, do not select the USPOOF_ANY_CASE option.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param s1 The first of the two strings to be compared for
+ * confusability. The strings are in UTF-16 format.
+ * @param length1 the length of the first string, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * zero terminated.
+ * @param s2 The second of the two strings to be compared for
+ * confusability. The strings are in UTF-16 format.
+ * @param length2 The length of the second string, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * zero terminated.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the strings is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the strings
+ * are not confusable.
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+ const UChar *s1, int32_t length1,
+ const UChar *s2, int32_t length2,
+ UErrorCode *status);
+
+
+
+/**
+ * Check the whether two specified strings are visually confusable.
+ * The types of confusability to be tested - single script, mixed script,
+ * or whole script - are determined by the check options set for the
+ * USpoofChecker.
+ *
+ * @param sc The USpoofChecker
+ * @param s1 The first of the two strings to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param length1 the length of the first string, in bytes, or -1
+ * if the string is zero terminated.
+ * @param s2 The second of the two strings to be compared for
+ * confusability. The strings are in UTF-18 format.
+ * @param length2 The length of the second string in bytes, or -1
+ * if the string is zero terminated.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the strings is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the strings
+ * are not confusable.
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+ const char *s1, int32_t length1,
+ const char *s2, int32_t length2,
+ UErrorCode *status);
+
+
+
+
+#if U_SHOW_CPLUSPLUS_API
+/**
+ * Check the whether two specified strings are visually confusable.
+ * The types of confusability to be tested - single script, mixed script,
+ * or whole script - are determined by the check options set for the
+ * USpoofChecker.
+ *
+ * @param sc The USpoofChecker
+ * @param s1 The first of the two strings to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param s2 The second of the two strings to be compared for
+ * confusability. The strings are in UTF-18 format.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the strings is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the strings
+ * are not confusable.
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+ const U_NAMESPACE_QUALIFIER UnicodeString &s1,
+ const U_NAMESPACE_QUALIFIER UnicodeString &s2,
+ UErrorCode *status);
+#endif
+
+
+/**
+ * Get the "skeleton" for an identifier string.
+ * Skeletons are a transformation of the input string;
+ * Two strings are confusable if their skeletons are identical.
+ * See Unicode UAX 39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker
+ * @param type The type of skeleton, corresponding to which
+ * of the Unicode confusable data tables to use.
+ * The default is Mixed-Script, Lowercase.
+ * Allowed options are USPOOF_SINGLE_SCRIPT_CONFUSABLE and
+ * USPOOF_ANY_CASE_CONFUSABLE. The two flags may be ORed.
+ * @param s The input string whose skeleton will be computed.
+ * @param length The length of the input string, expressed in 16 bit
+ * UTF-16 code units, or -1 if the string is zero terminated.
+ * @param dest The output buffer, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in 16 bit units.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * @return The length of the skeleton string. The returned length
+ * is always that of the complete skeleton, even when the
+ * supplied buffer is too small (or of zero length)
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+ uint32_t type,
+ const UChar *s, int32_t length,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * Get the "skeleton" for an identifier string.
+ * Skeletons are a transformation of the input string;
+ * Two strings are confusable if their skeletons are identical.
+ * See Unicode UAX 39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker
+ * @param type The type of skeleton, corresponding to which
+ * of the Unicode confusable data tables to use.
+ * The default is Mixed-Script, Lowercase.
+ * Allowed options are USPOOF_SINGLE_SCRIPT_CONFUSABLE and
+ * USPOOF_ANY_CASE. The two flags may be ORed.
+ * @param s The UTF-8 format input string whose skeleton will be computed.
+ * @param length The length of the input string, in bytes,
+ * or -1 if the string is zero terminated.
+ * @param dest The output buffer, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in bytes.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check. Possible Errors include U_INVALID_CHAR_FOUND
+ * for invalid UTF-8 sequences, and
+ * U_BUFFER_OVERFLOW_ERROR if the destination buffer is too small
+ * to hold the complete skeleton.
+ * @return The length of the skeleton string, in bytes. The returned length
+ * is always that of the complete skeleton, even when the
+ * supplied buffer is too small (or of zero length)
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+ uint32_t type,
+ const char *s, int32_t length,
+ char *dest, int32_t destCapacity,
+ UErrorCode *status);
+
+#if U_SHOW_CPLUSPLUS_API
+/**
+ * Get the "skeleton" for an identifier string.
+ * Skeletons are a transformation of the input string;
+ * Two strings are confusable if their skeletons are identical.
+ * See Unicode UAX 39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker.
+ * @param type The type of skeleton, corresponding to which
+ * of the Unicode confusable data tables to use.
+ * The default is Mixed-Script, Lowercase.
+ * Allowed options are USPOOF_SINGLE_SCRIPT_CONFUSABLE and
+ * USPOOF_ANY_CASE_CONFUSABLE. The two flags may be ORed.
+ * @param s The input string whose skeleton will be computed.
+ * @param dest The output string, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in bytes.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * @return A reference to the destination (skeleton) string.
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE UnicodeString & U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+ uint32_t type,
+ const UnicodeString &s,
+ UnicodeString &dest,
+ UErrorCode *status);
+#endif /* U_SHOW_CPLUSPLUS_API */
+
+
+/**
+ * Serialize the data for a spoof detector into a chunk of memory.
+ * The flattened spoof detection tables can later be used to efficiently
+ * instantiate a new Spoof Detector.
+ *
+ * @param sc the Spoof Detector whose data is to be serialized.
+ * @param data a pointer to 32-bit-aligned memory to be filled with the data,
+ * can be NULL if capacity==0
+ * @param capacity the number of bytes available at data,
+ * or 0 for preflighting
+ * @param status an in/out ICU UErrorCode; possible errors include:
+ * - U_BUFFER_OVERFLOW_ERROR if the data storage block is too small for serialization
+ * - U_ILLEGAL_ARGUMENT_ERROR the data or capacity parameters are bad
+ * @return the number of bytes written or needed for the spoof data
+ *
+ * @see utrie2_openFromSerialized()
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,
+ void *data, int32_t capacity,
+ UErrorCode *status);
+
+
+#endif
+
+#endif /* USPOOF_H */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/unicode/utmscale.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/utmscale.h
new file mode 100644
index 00000000000..472d776a62d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/utmscale.h
@@ -0,0 +1,481 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004 - 2008, 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).
+ *
+ * @stable 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-4.8.1/i18n/unicode/utrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/utrans.h
new file mode 100644
index 00000000000..5ef035fdd06
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/utrans.h
@@ -0,0 +1,603 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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/localpointer.h"
+#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);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUTransliteratorPointer
+ * "Smart pointer" class, closes a UTransliterator via utrans_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUTransliteratorPointer, UTransliterator, utrans_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * 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-4.8.1/i18n/unicode/vtzone.h b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/vtzone.h
new file mode 100644
index 00000000000..724da7e289b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unicode/vtzone.h
@@ -0,0 +1,455 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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. Or, you can create a
+ * <code>VTimeZone</code> from any other ICU <code>BasicTimeZone</code>.
+ * <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.
+ * @stable ICU 3.8
+ */
+class U_I18N_API VTimeZone : public BasicTimeZone {
+public:
+ /**
+ * Copy constructor.
+ * @param source The <code>VTimeZone</code> object to be copied.
+ * @stable ICU 3.8
+ */
+ VTimeZone(const VTimeZone& source);
+
+ /**
+ * Destructor.
+ * @stable ICU 3.8
+ */
+ virtual ~VTimeZone();
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ static VTimeZone* createVTimeZoneByID(const UnicodeString& ID);
+
+ /**
+ * Create a <code>VTimeZone</code> instance using a basic time zone.
+ * @param basicTZ The basic time zone instance
+ * @param status Output param to filled in with a success or an error.
+ * @return A <code>VTimeZone</code> object initialized by the basic time zone.
+ * @draft ICU 4.6
+ */
+ static VTimeZone* createVTimeZoneFromBasicTimeZone(const BasicTimeZone& basicTZ,
+ UErrorCode &status);
+
+ /**
+ * 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.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ UBool getTZURL(UnicodeString& url) const;
+
+ /**
+ * Sets the RFC2445 TZURL property value.
+ * @param url The TZURL property value.
+ * @stable 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.
+ * @stable ICU 3.8
+ */
+ UBool getLastModified(UDate& lastModified) const;
+
+ /**
+ * Sets the RFC2445 LAST-MODIFIED property value.
+ * @param lastModified The LAST-MODIFIED date.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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.
+ * @stable 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& zonename,
+ int32_t fromOffset, int32_t toOffset, UDate time, UBool withRDATE,
+ UErrorCode& status) const;
+ void writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
+ 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& zonename,
+ 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& zonename,
+ 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& zonename,
+ 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& zonename,
+ 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.
+ * @stable 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.
+ * @stable 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-4.8.1/i18n/unum.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/unum.cpp
new file mode 100644
index 00000000000..331049ee317
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/unum.cpp
@@ -0,0 +1,908 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2011, 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"
+#include "cstring.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 NULL;
+ }
+
+ NumberFormat *retVal = NULL;
+
+ switch(style) {
+ case UNUM_DECIMAL:
+ case UNUM_CURRENCY:
+ case UNUM_PERCENT:
+ case UNUM_SCIENTIFIC:
+ retVal = NumberFormat::createInstance(Locale(locale), style, *status);
+ break;
+
+ case UNUM_PATTERN_DECIMAL: {
+ UParseError tErr;
+ /* UnicodeString can handle the case when patternLength = -1. */
+ const UnicodeString pat(pattern, patternLength);
+
+ if(parseErr==NULL){
+ parseErr = &tErr;
+ }
+
+ DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
+ if(syms == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_FAILURE(*status)) {
+ delete syms;
+ return NULL;
+ }
+
+ retVal = new DecimalFormat(pat, syms, *parseErr, *status);
+ if(retVal == NULL) {
+ 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 = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
+ } break;
+
+ case UNUM_SPELLOUT:
+ retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
+ break;
+
+ case UNUM_ORDINAL:
+ retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
+ break;
+
+ case UNUM_DURATION:
+ retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
+ break;
+
+ case UNUM_NUMBERING_SYSTEM:
+ retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
+ break;
+#endif
+
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+
+ if(retVal == NULL && U_SUCCESS(*status)) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ return reinterpret_cast<UNumberFormat *>(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;
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+ if (df != NULL) {
+ res = df->clone();
+ } else {
+ const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+ U_ASSERT(rbnf != NULL);
+ res = rbnf->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_DRAFT int32_t U_EXPORT2
+unum_formatDecimal(const UNumberFormat* fmt,
+ const char * number,
+ int32_t length,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos, /* 0 if ignore */
+ UErrorCode* status) {
+
+ if(U_FAILURE(*status)) {
+ return -1;
+ }
+ if ((result == NULL && resultLength != 0) || resultLength < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ FieldPosition fp;
+ if(pos != 0) {
+ fp.setField(pos->field);
+ }
+
+ if (length < 0) {
+ length = uprv_strlen(number);
+ }
+ StringPiece numSP(number, length);
+ Formattable numFmtbl(numSP, *status);
+
+ UnicodeString resultStr;
+ if (resultLength > 0) {
+ // Alias the destination buffer.
+ resultStr.setTo(result, 0, resultLength);
+ }
+ ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
+ if(pos != 0) {
+ pos->beginIndex = fp.getBeginIndex();
+ pos->endIndex = fp.getEndIndex();
+ }
+ return resultStr.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);
+ }
+ CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
+ // Check for null pointer.
+ if (tempCurrAmnt == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+ Formattable n(tempCurrAmnt);
+ ((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(pp.getErrorIndex() != -1) {
+ *status = U_PARSE_ERROR;
+ if(parsePos != 0) {
+ *parsePos = pp.getErrorIndex();
+ }
+ } else if(parsePos != 0) {
+ *parsePos = pp.getIndex();
+ }
+}
+
+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 int32_t U_EXPORT2
+unum_parseDecimal(const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ char *outBuf,
+ int32_t outBufLength,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return -1;
+ }
+ if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ Formattable res;
+ parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+ StringPiece sp = res.getDecimalNumber(*status);
+ if (U_FAILURE(*status)) {
+ return -1;
+ } else if (sp.size() > outBufLength) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ } else if (sp.size() == outBufLength) {
+ uprv_strncpy(outBuf, sp.data(), sp.size());
+ *status = U_STRING_NOT_TERMINATED_WARNING;
+ } else {
+ uprv_strcpy(outBuf, sp.data());
+ }
+ return sp.size();
+}
+
+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;
+ const CurrencyAmount* c;
+ if (res.getType() == Formattable::kObject &&
+ (c = dynamic_cast<const CurrencyAmount*>(res.getObject())) != NULL) {
+ 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)
+{
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ if ( attr == UNUM_LENIENT_PARSE ) {
+ // Supported for all subclasses
+ return nf->isLenient();
+ }
+ // The remaining attributea are only supported for DecimalFormat
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+ if (df != NULL) {
+ 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;
+ }
+ }
+
+ return -1;
+}
+
+U_CAPI void U_EXPORT2
+unum_setAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ int32_t newValue)
+{
+ NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+ if ( attr == UNUM_LENIENT_PARSE ) {
+ // Supported for all subclasses
+ return nf->setLenient(newValue != 0);
+ }
+ // The remaining attributea are only supported for DecimalFormat
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+ if (df != NULL) {
+ 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;
+ }
+ }
+}
+
+U_CAPI double U_EXPORT2
+unum_getDoubleAttribute(const UNumberFormat* fmt,
+ UNumberFormatAttribute attr)
+{
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+ if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
+ return df->getRoundingIncrement();
+ } else {
+ return -1.0;
+ }
+}
+
+U_CAPI void U_EXPORT2
+unum_setDoubleAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ double newValue)
+{
+ NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+ if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
+ df->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);
+ }
+
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+ if (df != NULL) {
+ 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 {
+ const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+ U_ASSERT(rbnf != NULL);
+ 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);
+ NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+ if (df != NULL) {
+ 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 {
+ RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
+ U_ASSERT(rbnf != NULL);
+ if (tag == UNUM_DEFAULT_RULESET) {
+ rbnf->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);
+ }
+
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+ if (df != NULL) {
+ if(isPatternLocalized)
+ df->toLocalizedPattern(pat);
+ else
+ df->toPattern(pat);
+ } else {
+ const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+ U_ASSERT(rbnf != NULL);
+ pat = rbnf->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 || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
+ const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
+ if (dcf == NULL) {
+ *status = U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ return dcf->
+ 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 || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
+ DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
+ if (dcf == NULL) {
+ *status = U_UNSUPPORTED_ERROR;
+ return;
+ }
+
+ DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
+ symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
+ UnicodeString(value, length)); /* UnicodeString can handle the case when length = -1. */
+ dcf->setDecimalFormatSymbols(symbols);
+}
+
+U_CAPI void U_EXPORT2
+unum_applyPattern( UNumberFormat *fmt,
+ 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
+ NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+ if (df != NULL) {
+ if(localized) {
+ df->applyLocalizedPattern(pat,*parseError, *status);
+ } else {
+ df->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-4.8.1/i18n/upluralrules.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/upluralrules.cpp
new file mode 100644
index 00000000000..5e95125c3f4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/upluralrules.cpp
@@ -0,0 +1,51 @@
+/*
+*****************************************************************************************
+* Copyright (C) 2010-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*****************************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/upluralrules.h"
+#include "unicode/plurrule.h"
+#include "unicode/locid.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_USE
+
+
+U_CAPI UPluralRules* U_EXPORT2
+uplrules_open(const char *locale,
+ UErrorCode *status)
+{
+ return (UPluralRules*)PluralRules::forLocale(Locale(locale), *status);
+}
+
+U_CAPI void U_EXPORT2
+uplrules_close(UPluralRules *uplrules)
+{
+ delete (PluralRules*)uplrules;
+}
+
+U_CAPI int32_t U_EXPORT2
+uplrules_select(const UPluralRules *uplrules,
+ double number,
+ UChar *keyword, int32_t capacity,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (keyword == NULL ? capacity != 0 : capacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString result = ((PluralRules*)uplrules)->select(number);
+ return result.extract(keyword, capacity, *status);
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uregex.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uregex.cpp
new file mode 100644
index 00000000000..4dd50f10f11
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uregex.cpp
@@ -0,0 +1,1942 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2011, 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"
+
+#include "regextxt.h"
+
+#include <stdio.h>
+
+U_NAMESPACE_BEGIN
+
+#define REMAINING_CAPACITY(idx,len) ((((len)-(idx))>0)?((len)-(idx)):0)
+
+struct RegularExpression: public UMemory {
+public:
+ RegularExpression();
+ ~RegularExpression();
+ 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.
+ UBool fOwnsText;
+};
+
+static const int32_t REXP_MAGIC = 0x72657870; // "rexp" in ASCII
+
+RegularExpression::RegularExpression() {
+ fMagic = REXP_MAGIC;
+ fPat = NULL;
+ fPatRefCount = NULL;
+ fPatString = NULL;
+ fPatStringLen = 0;
+ fMatcher = NULL;
+ fText = NULL;
+ fTextLength = 0;
+ fOwnsText = FALSE;
+}
+
+RegularExpression::~RegularExpression() {
+ delete fMatcher;
+ fMatcher = NULL;
+ if (fPatRefCount!=NULL && umtx_atomic_dec(fPatRefCount)==0) {
+ delete fPat;
+ uprv_free(fPatString);
+ uprv_free(fPatRefCount);
+ }
+ if (fOwnsText && fText!=NULL) {
+ uprv_free((void *)fText);
+ }
+ fMagic = 0;
+}
+
+U_NAMESPACE_END
+
+U_NAMESPACE_USE
+
+//----------------------------------------------------------------------------------------
+//
+// validateRE Do boilerplate style checks on API function parameters.
+// Return TRUE if they look OK.
+//----------------------------------------------------------------------------------------
+static UBool validateRE(const RegularExpression *re, UBool requiresText, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (re == NULL || re->fMagic != REXP_MAGIC) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+ // !!! Not sure how to update this with the new UText backing, which is stored in re->fMatcher anyway
+ if (requiresText && re->fText == NULL && !re->fOwnsText) {
+ *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);
+ }
+
+ RegularExpression *re = new RegularExpression;
+ 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 UText wrapper around
+ // this local copy, to avoid making even more copies.
+ //
+ re->fPatString = patBuf;
+ re->fPatStringLen = patternLength;
+ u_memcpy(patBuf, pattern, actualPatLen);
+ patBuf[actualPatLen] = 0;
+
+ UText patText = UTEXT_INITIALIZER;
+ utext_openUChars(&patText, patBuf, patternLength, status);
+
+ //
+ // Compile the pattern
+ //
+ if (pe != NULL) {
+ re->fPat = RegexPattern::compile(&patText, flags, *pe, *status);
+ } else {
+ re->fPat = RegexPattern::compile(&patText, flags, *status);
+ }
+ utext_close(&patText);
+
+ if (U_FAILURE(*status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Create the matcher object
+ //
+ re->fMatcher = re->fPat->matcher(*status);
+ if (U_SUCCESS(*status)) {
+ return (URegularExpression*)re;
+ }
+
+ErrorExit:
+ delete re;
+ return NULL;
+
+}
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_openUText
+//
+//----------------------------------------------------------------------------------------
+U_CAPI URegularExpression * U_EXPORT2
+uregex_openUText(UText *pattern,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status) {
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (pattern == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ int64_t patternNativeLength = utext_nativeLength(pattern);
+
+ if (patternNativeLength == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ RegularExpression *re = new RegularExpression;
+
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ int32_t pattern16Length = utext_extract(pattern, 0, patternNativeLength, NULL, 0, &lengthStatus);
+
+ int32_t *refC = (int32_t *)uprv_malloc(sizeof(int32_t));
+ UChar *patBuf = (UChar *)uprv_malloc(sizeof(UChar)*(pattern16Length+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 UText wrapper
+ // around this local copy, to avoid making even more copies.
+ //
+ re->fPatString = patBuf;
+ re->fPatStringLen = pattern16Length;
+ utext_extract(pattern, 0, patternNativeLength, patBuf, pattern16Length+1, status);
+
+ UText patText = UTEXT_INITIALIZER;
+ utext_openUChars(&patText, patBuf, pattern16Length, status);
+
+ //
+ // Compile the pattern
+ //
+ if (pe != NULL) {
+ re->fPat = RegexPattern::compile(&patText, flags, *pe, *status);
+ } else {
+ re->fPat = RegexPattern::compile(&patText, flags, *status);
+ }
+ utext_close(&patText);
+
+ if (U_FAILURE(*status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Create the matcher object
+ //
+ re->fMatcher = re->fPat->matcher(*status);
+ if (U_SUCCESS(*status)) {
+ return (URegularExpression*)re;
+ }
+
+ErrorExit:
+ delete re;
+ return NULL;
+
+}
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_close
+//
+//----------------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_close(URegularExpression *re2) {
+ RegularExpression *re = (RegularExpression*)re2;
+ UErrorCode status = U_ZERO_ERROR;
+ if (validateRE(re, FALSE, &status) == FALSE) {
+ return;
+ }
+ delete re;
+}
+
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_clone
+//
+//----------------------------------------------------------------------------------------
+U_CAPI URegularExpression * U_EXPORT2
+uregex_clone(const URegularExpression *source2, UErrorCode *status) {
+ RegularExpression *source = (RegularExpression*)source2;
+ if (validateRE(source, FALSE, status) == FALSE) {
+ return NULL;
+ }
+
+ RegularExpression *clone = new RegularExpression;
+ if (clone == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ clone->fMatcher = source->fPat->matcher(*status);
+ if (U_FAILURE(*status)) {
+ delete clone;
+ 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 (URegularExpression*)clone;
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_pattern
+//
+//------------------------------------------------------------------------------
+U_CAPI const UChar * U_EXPORT2
+uregex_pattern(const URegularExpression *regexp2,
+ int32_t *patLength,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return NULL;
+ }
+ if (patLength != NULL) {
+ *patLength = regexp->fPatStringLen;
+ }
+ return regexp->fPatString;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_patternUText
+//
+//------------------------------------------------------------------------------
+U_CAPI UText * U_EXPORT2
+uregex_patternUText(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ return regexp->fPat->patternText(*status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_flags
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_flags(const URegularExpression *regexp2, UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return 0;
+ }
+ int32_t flags = regexp->fPat->flags();
+ return flags;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setText
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setText(URegularExpression *regexp2,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return;
+ }
+ if (text == NULL || textLength < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ if (regexp->fOwnsText && regexp->fText != NULL) {
+ uprv_free((void *)regexp->fText);
+ }
+
+ regexp->fText = text;
+ regexp->fTextLength = textLength;
+ regexp->fOwnsText = FALSE;
+
+ UText input = UTEXT_INITIALIZER;
+ utext_openUChars(&input, text, textLength, status);
+ regexp->fMatcher->reset(&input);
+ utext_close(&input); // reset() made a shallow clone, so we don't need this copy
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setUText
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setUText(URegularExpression *regexp2,
+ UText *text,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return;
+ }
+ if (text == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ if (regexp->fOwnsText && regexp->fText != NULL) {
+ uprv_free((void *)regexp->fText);
+ }
+
+ regexp->fText = NULL; // only fill it in on request
+ regexp->fTextLength = -1;
+ regexp->fOwnsText = TRUE;
+ regexp->fMatcher->reset(text);
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getText
+//
+//------------------------------------------------------------------------------
+U_CAPI const UChar * U_EXPORT2
+uregex_getText(URegularExpression *regexp2,
+ int32_t *textLength,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return NULL;
+ }
+
+ if (regexp->fText == NULL) {
+ // need to fill in the text
+ UText *inputText = regexp->fMatcher->inputText();
+ int64_t inputNativeLength = utext_nativeLength(inputText);
+ if (UTEXT_FULL_TEXT_IN_CHUNK(inputText, inputNativeLength)) {
+ regexp->fText = inputText->chunkContents;
+ regexp->fTextLength = (int32_t)inputNativeLength;
+ regexp->fOwnsText = FALSE; // because the UText owns it
+ } else {
+ UErrorCode lengthStatus = U_ZERO_ERROR;
+ regexp->fTextLength = utext_extract(inputText, 0, inputNativeLength, NULL, 0, &lengthStatus); // buffer overflow error
+ UChar *inputChars = (UChar *)uprv_malloc(sizeof(UChar)*(regexp->fTextLength+1));
+
+ utext_extract(inputText, 0, inputNativeLength, inputChars, regexp->fTextLength+1, status);
+ regexp->fText = inputChars;
+ regexp->fOwnsText = TRUE; // should already be set but just in case
+ }
+ }
+
+ if (textLength != NULL) {
+ *textLength = regexp->fTextLength;
+ }
+ return regexp->fText;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getUText
+//
+//------------------------------------------------------------------------------
+U_CAPI UText * U_EXPORT2
+uregex_getUText(URegularExpression *regexp2,
+ UText *dest,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return dest;
+ }
+ return regexp->fMatcher->getInput(dest, *status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_refreshUText
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_refreshUText(URegularExpression *regexp2,
+ UText *text,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->refreshInputText(text, *status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_matches
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_matches(URegularExpression *regexp2,
+ int32_t startIndex,
+ UErrorCode *status) {
+ return uregex_matches64( regexp2, (int64_t)startIndex, status);
+}
+
+U_CAPI UBool U_EXPORT2
+uregex_matches64(URegularExpression *regexp2,
+ int64_t startIndex,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ UBool result = FALSE;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return result;
+ }
+ if (startIndex == -1) {
+ result = regexp->fMatcher->matches(*status);
+ } else {
+ result = regexp->fMatcher->matches(startIndex, *status);
+ }
+ return result;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_lookingAt
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_lookingAt(URegularExpression *regexp2,
+ int32_t startIndex,
+ UErrorCode *status) {
+ return uregex_lookingAt64( regexp2, (int64_t)startIndex, status);
+}
+
+U_CAPI UBool U_EXPORT2
+uregex_lookingAt64(URegularExpression *regexp2,
+ int64_t startIndex,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ UBool result = FALSE;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return result;
+ }
+ if (startIndex == -1) {
+ result = regexp->fMatcher->lookingAt(*status);
+ } else {
+ result = regexp->fMatcher->lookingAt(startIndex, *status);
+ }
+ return result;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_find
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_find(URegularExpression *regexp2,
+ int32_t startIndex,
+ UErrorCode *status) {
+ return uregex_find64( regexp2, (int64_t)startIndex, status);
+}
+
+U_CAPI UBool U_EXPORT2
+uregex_find64(URegularExpression *regexp2,
+ int64_t startIndex,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ UBool result = FALSE;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return result;
+ }
+ if (startIndex == -1) {
+ regexp->fMatcher->resetPreserveRegion();
+ result = regexp->fMatcher->find();
+ } else {
+ result = regexp->fMatcher->find(startIndex, *status);
+ }
+ return result;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_findNext
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_findNext(URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return FALSE;
+ }
+ UBool result = regexp->fMatcher->find();
+ return result;
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_groupCount
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_groupCount(URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return 0;
+ }
+ int32_t result = regexp->fMatcher->groupCount();
+ return result;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_group
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_group(URegularExpression *regexp2,
+ int32_t groupNum,
+ UChar *dest,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if (destCapacity == 0 || regexp->fText != NULL) {
+ // If preflighting or if we already have the text as UChars,
+ // this is a little cheaper than going through uregex_groupUTextDeep()
+
+ //
+ // 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;
+ } else {
+ UText *groupText = uregex_groupUTextDeep(regexp2, groupNum, NULL, status);
+ int32_t result = utext_extract(groupText, 0, utext_nativeLength(groupText), dest, destCapacity, status);
+ utext_close(groupText);
+ return result;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_groupUText
+//
+//------------------------------------------------------------------------------
+U_CAPI UText * U_EXPORT2
+uregex_groupUText(URegularExpression *regexp2,
+ int32_t groupNum,
+ UText *dest,
+ int64_t *groupLength,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ UErrorCode emptyTextStatus = U_ZERO_ERROR;
+ return (dest ? dest : utext_openUChars(NULL, NULL, 0, &emptyTextStatus));
+ }
+
+ return regexp->fMatcher->group(groupNum, dest, *groupLength, *status);
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_groupUTextDeep
+//
+//------------------------------------------------------------------------------
+U_CAPI UText * U_EXPORT2
+uregex_groupUTextDeep(URegularExpression *regexp2,
+ int32_t groupNum,
+ UText *dest,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ UErrorCode emptyTextStatus = U_ZERO_ERROR;
+ return (dest ? dest : utext_openUChars(NULL, NULL, 0, &emptyTextStatus));
+ }
+
+ if (regexp->fText != NULL) {
+ //
+ // Pick up the range of characters from the matcher
+ // and use our already-extracted characters
+ //
+ int32_t startIx = regexp->fMatcher->start(groupNum, *status);
+ int32_t endIx = regexp->fMatcher->end (groupNum, *status);
+ if (U_FAILURE(*status)) {
+ UErrorCode emptyTextStatus = U_ZERO_ERROR;
+ return (dest ? dest : utext_openUChars(NULL, NULL, 0, &emptyTextStatus));
+ }
+
+ if (dest) {
+ utext_replace(dest, 0, utext_nativeLength(dest), &regexp->fText[startIx], endIx - startIx, status);
+ } else {
+ UText groupText = UTEXT_INITIALIZER;
+ utext_openUChars(&groupText, &regexp->fText[startIx], endIx - startIx, status);
+ dest = utext_clone(NULL, &groupText, TRUE, FALSE, status);
+ utext_close(&groupText);
+ }
+
+ return dest;
+ } else {
+ return regexp->fMatcher->group(groupNum, dest, *status);
+ }
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_start
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_start(URegularExpression *regexp2,
+ int32_t groupNum,
+ UErrorCode *status) {
+ return (int32_t)uregex_start64( regexp2, groupNum, status);
+}
+
+U_CAPI int64_t U_EXPORT2
+uregex_start64(URegularExpression *regexp2,
+ int32_t groupNum,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, 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 *regexp2,
+ int32_t groupNum,
+ UErrorCode *status) {
+ return (int32_t)uregex_end64( regexp2, groupNum, status);
+}
+
+U_CAPI int64_t U_EXPORT2
+uregex_end64(URegularExpression *regexp2,
+ int32_t groupNum,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ int32_t result = regexp->fMatcher->end(groupNum, *status);
+ return result;
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_reset
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_reset(URegularExpression *regexp2,
+ int32_t index,
+ UErrorCode *status) {
+ uregex_reset64( regexp2, (int64_t)index, status);
+}
+
+U_CAPI void U_EXPORT2
+uregex_reset64(URegularExpression *regexp2,
+ int64_t index,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->reset(index, *status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setRegion
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setRegion(URegularExpression *regexp2,
+ int32_t regionStart,
+ int32_t regionLimit,
+ UErrorCode *status) {
+ uregex_setRegion64( regexp2, (int64_t)regionStart, (int64_t)regionLimit, status);
+}
+
+U_CAPI void U_EXPORT2
+uregex_setRegion64(URegularExpression *regexp2,
+ int64_t regionStart,
+ int64_t regionLimit,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->region(regionStart, regionLimit, *status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setRegionAndStart
+//
+//------------------------------------------------------------------------------
+U_DRAFT void U_EXPORT2
+uregex_setRegionAndStart(URegularExpression *regexp2,
+ int64_t regionStart,
+ int64_t regionLimit,
+ int64_t startIndex,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->region(regionStart, regionLimit, startIndex, *status);
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_regionStart
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_regionStart(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ return (int32_t)uregex_regionStart64(regexp2, status);
+}
+
+U_CAPI int64_t U_EXPORT2
+uregex_regionStart64(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ return regexp->fMatcher->regionStart();
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_regionEnd
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_regionEnd(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ return (int32_t)uregex_regionEnd64(regexp2, status);
+}
+
+U_CAPI int64_t U_EXPORT2
+uregex_regionEnd64(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ return regexp->fMatcher->regionEnd();
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_hasTransparentBounds
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_hasTransparentBounds(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return FALSE;
+ }
+ return regexp->fMatcher->hasTransparentBounds();
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_useTransparentBounds
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_useTransparentBounds(URegularExpression *regexp2,
+ UBool b,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->useTransparentBounds(b);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_hasAnchoringBounds
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_hasAnchoringBounds(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return FALSE;
+ }
+ return regexp->fMatcher->hasAnchoringBounds();
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_useAnchoringBounds
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_useAnchoringBounds(URegularExpression *regexp2,
+ UBool b,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->useAnchoringBounds(b);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_hitEnd
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_hitEnd(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return FALSE;
+ }
+ return regexp->fMatcher->hitEnd();
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_requireEnd
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_requireEnd(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return FALSE;
+ }
+ return regexp->fMatcher->requireEnd();
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setTimeLimit
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setTimeLimit(URegularExpression *regexp2,
+ int32_t limit,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ regexp->fMatcher->setTimeLimit(limit, *status);
+ }
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getTimeLimit
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_getTimeLimit(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ int32_t retVal = 0;
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ retVal = regexp->fMatcher->getTimeLimit();
+ }
+ return retVal;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setStackLimit
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setStackLimit(URegularExpression *regexp2,
+ int32_t limit,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ regexp->fMatcher->setStackLimit(limit, *status);
+ }
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getStackLimit
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_getStackLimit(const URegularExpression *regexp2,
+ UErrorCode *status) {
+ int32_t retVal = 0;
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ retVal = regexp->fMatcher->getStackLimit();
+ }
+ return retVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setMatchCallback
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setMatchCallback(URegularExpression *regexp2,
+ URegexMatchCallback *callback,
+ const void *context,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ regexp->fMatcher->setMatchCallback(callback, context, *status);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getMatchCallback
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_getMatchCallback(const URegularExpression *regexp2,
+ URegexMatchCallback **callback,
+ const void **context,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ regexp->fMatcher->getMatchCallback(*callback, *context, *status);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setMatchProgressCallback
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setFindProgressCallback(URegularExpression *regexp2,
+ URegexFindProgressCallback *callback,
+ const void *context,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ regexp->fMatcher->setFindProgressCallback(callback, context, *status);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getMatchCallback
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_getFindProgressCallback(const URegularExpression *regexp2,
+ URegexFindProgressCallback **callback,
+ const void **context,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, FALSE, status)) {
+ regexp->fMatcher->getFindProgressCallback(*callback, *context, *status);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_replaceAll
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_replaceAll(URegularExpression *regexp2,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, 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(regexp2, 0, status);
+
+ // Note: Seperate error code variables for findNext() and appendReplacement()
+ // are used so that destination buffer overflow errors
+ // in appendReplacement won't stop findNext() from working.
+ // appendReplacement() and appendTail() special case incoming buffer
+ // overflow errors, continuing to return the correct length.
+ UErrorCode findStatus = *status;
+ while (uregex_findNext(regexp2, &findStatus)) {
+ len += uregex_appendReplacement(regexp2, replacementText, replacementLength,
+ &destBuf, &destCapacity, status);
+ }
+ len += uregex_appendTail(regexp2, &destBuf, &destCapacity, status);
+
+ if (U_FAILURE(findStatus)) {
+ // If anything went wrong with the findNext(), make that error trump
+ // whatever may have happened with the append() operations.
+ // Errors in findNext() are not expected.
+ *status = findStatus;
+ }
+
+ return len;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_replaceAllUText
+//
+//------------------------------------------------------------------------------
+U_CAPI UText * U_EXPORT2
+uregex_replaceAllUText(URegularExpression *regexp2,
+ UText *replacementText,
+ UText *dest,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ if (replacementText == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ dest = regexp->fMatcher->replaceAll(replacementText, dest, *status);
+ return dest;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_replaceFirst
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_replaceFirst(URegularExpression *regexp2,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, 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(regexp2, 0, status);
+ findSucceeded = uregex_find(regexp2, 0, status);
+ if (findSucceeded) {
+ len = uregex_appendReplacement(regexp2, replacementText, replacementLength,
+ &destBuf, &destCapacity, status);
+ }
+ len += uregex_appendTail(regexp2, &destBuf, &destCapacity, status);
+
+ return len;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_replaceFirstUText
+//
+//------------------------------------------------------------------------------
+U_CAPI UText * U_EXPORT2
+uregex_replaceFirstUText(URegularExpression *regexp2,
+ UText *replacementText,
+ UText *dest,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ if (replacementText == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ dest = regexp->fMatcher->replaceFirst(replacementText, dest, *status);
+ return dest;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_appendReplacement
+//
+//------------------------------------------------------------------------------
+
+U_NAMESPACE_BEGIN
+//
+// Dummy class, because these functions need to be friends of class RegexMatcher,
+// and stand-alone C functions don't work as friends
+//
+class RegexCImpl {
+ public:
+ inline static int32_t appendReplacement(RegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status);
+
+ inline static int32_t appendTail(RegularExpression *regexp,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status);
+
+ inline static int32_t split(RegularExpression *regexp,
+ UChar *destBuf,
+ int32_t destCapacity,
+ int32_t *requiredCapacity,
+ UChar *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status);
+};
+
+U_NAMESPACE_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(RegularExpression *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 != NULL && *destCapacity == 0) {
+ pendingBufferOverflow = TRUE;
+ *status = U_ZERO_ERROR;
+ }
+
+ //
+ // Validate all paramters
+ //
+ if (validateRE(regexp, TRUE, 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
+ if (regexp->fText != NULL) {
+ int32_t matchStart;
+ int32_t lastMatchEnd;
+ if (UTEXT_USES_U16(m->fInputText)) {
+ lastMatchEnd = (int32_t)m->fLastMatchEnd;
+ matchStart = (int32_t)m->fMatchStart;
+ } else {
+ // !!!: Would like a better way to do this!
+ UErrorCode status = U_ZERO_ERROR;
+ lastMatchEnd = utext_extract(m->fInputText, 0, m->fLastMatchEnd, NULL, 0, &status);
+ status = U_ZERO_ERROR;
+ matchStart = lastMatchEnd + utext_extract(m->fInputText, m->fLastMatchEnd, m->fMatchStart, NULL, 0, &status);
+ }
+ for (i=lastMatchEnd; i<matchStart; i++) {
+ appendToBuf(regexp->fText[i], &destIdx, dest, capacity);
+ }
+ } else {
+ UErrorCode possibleOverflowError = U_ZERO_ERROR; // ignore
+ destIdx += utext_extract(m->fInputText, m->fLastMatchEnd, m->fMatchStart,
+ &dest[destIdx], REMAINING_CAPACITY(destIdx, capacity), &possibleOverflowError);
+ }
+
+
+ // 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(uregex_ucstr_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.
+ destIdx += uregex_group((URegularExpression*)regexp, groupNum, &dest[destIdx], REMAINING_CAPACITY(destIdx, capacity), 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 actual API function,
+//
+U_CAPI int32_t U_EXPORT2
+uregex_appendReplacement(URegularExpression *regexp2,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status) {
+
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ return RegexCImpl::appendReplacement(
+ regexp, replacementText, replacementLength,destBuf, destCapacity, status);
+}
+
+//
+// uregex_appendReplacementUText...can just use the normal C++ method
+//
+U_CAPI void U_EXPORT2
+uregex_appendReplacementUText(URegularExpression *regexp2,
+ UText *replText,
+ UText *dest,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ regexp->fMatcher->appendReplacement(dest, replText, *status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_appendTail
+//
+//------------------------------------------------------------------------------
+int32_t RegexCImpl::appendTail(RegularExpression *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 != NULL && *destCapacity == 0) {
+ pendingBufferOverflow = TRUE;
+ *status = U_ZERO_ERROR;
+ }
+
+ if (validateRE(regexp, TRUE, 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 destIdx = 0;
+ int32_t destCap = *destCapacity;
+ UChar *dest = *destBuf;
+
+ if (regexp->fText != NULL) {
+ int32_t srcIdx;
+ int64_t nativeIdx = (m->fMatch ? m->fMatchEnd : m->fLastMatchEnd);
+ if (nativeIdx == -1) {
+ srcIdx = 0;
+ } else if (UTEXT_USES_U16(m->fInputText)) {
+ srcIdx = (int32_t)nativeIdx;
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &status);
+ }
+
+ for (;;) {
+ if (srcIdx == regexp->fTextLength) {
+ break;
+ }
+ UChar c = regexp->fText[srcIdx];
+ if (c == 0 && regexp->fTextLength == -1) {
+ regexp->fTextLength = srcIdx;
+ 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++;
+ }
+ } else {
+ int64_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;
+ }
+ }
+
+ destIdx = utext_extract(m->fInputText, srcIdx, m->fInputLength, dest, destCap, status);
+ }
+
+ //
+ // 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;
+}
+
+
+//
+// appendTail the actual API function
+//
+U_CAPI int32_t U_EXPORT2
+uregex_appendTail(URegularExpression *regexp2,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ return RegexCImpl::appendTail(regexp, destBuf, destCapacity, status);
+}
+
+
+//
+// uregex_appendTailUText...can just use the normal C++ method
+//
+U_CAPI UText * U_EXPORT2
+uregex_appendTailUText(URegularExpression *regexp2,
+ UText *dest,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ return regexp->fMatcher->appendTail(dest, *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.
+//
+//------------------------------------------------------------------------------
+#if 0
+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;
+}
+#endif
+
+//------------------------------------------------------------------------------
+//
+// uregex_split
+//
+//------------------------------------------------------------------------------
+int32_t RegexCImpl::split(RegularExpression *regexp,
+ UChar *destBuf,
+ int32_t destCapacity,
+ int32_t *requiredCapacity,
+ UChar *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status) {
+ //
+ // Reset for the input text
+ //
+ regexp->fMatcher->reset();
+ UText *inputText = regexp->fMatcher->fInputText;
+ int64_t nextOutputStringStart = 0;
+ int64_t inputLen = regexp->fMatcher->fInputLength;
+ 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();
+ UErrorCode tStatus = U_ZERO_ERROR; // Want to ignore any buffer overflow errors so that the strings are still counted
+ for (i=0; ; i++) {
+ if (i>=destFieldsCapacity-1) {
+ // There are one or zero output strings 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.)
+ if (inputLen > nextOutputStringStart) {
+ if (i != destFieldsCapacity-1) {
+ // 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];
+ destIdx += 1 + utext_extract(inputText, nextOutputStringStart, inputLen,
+ &destBuf[destIdx], REMAINING_CAPACITY(destIdx, destCapacity), status);
+ }
+ 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.
+ destFields[i] = &destBuf[destIdx];
+
+ destIdx += 1 + utext_extract(inputText, nextOutputStringStart, regexp->fMatcher->fMatchStart,
+ &destBuf[destIdx], REMAINING_CAPACITY(destIdx, destCapacity), &tStatus);
+ if (tStatus == U_BUFFER_OVERFLOW_ERROR) {
+ tStatus = U_ZERO_ERROR;
+ } else {
+ *status = tStatus;
+ }
+ nextOutputStringStart = regexp->fMatcher->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 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.
+ destFields[i] = &destBuf[destIdx];
+ tStatus = U_ZERO_ERROR;
+ int32_t t = uregex_group((URegularExpression*)regexp,
+ groupNum,
+ destFields[i],
+ REMAINING_CAPACITY(destIdx, destCapacity),
+ &tStatus);
+ destIdx += t + 1; // Record the space used in the output string buffer.
+ // +1 for the NUL that terminates the string.
+ if (tStatus == U_BUFFER_OVERFLOW_ERROR) {
+ tStatus = U_ZERO_ERROR;
+ } else {
+ *status = tStatus;
+ }
+ }
+
+ if (nextOutputStringStart == inputLen) {
+ // The delimiter was at the end of the string.
+ // Output an empty string, and then we are done.
+ if (destIdx < destCapacity) {
+ destBuf[destIdx] = 0;
+ }
+ if (i < destFieldsCapacity-1) {
+ ++i;
+ }
+ if (destIdx < destCapacity) {
+ destFields[i] = destBuf + destIdx;
+ }
+ ++destIdx;
+ 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];
+ destIdx += 1 + utext_extract(inputText, nextOutputStringStart, inputLen,
+ &destBuf[destIdx], REMAINING_CAPACITY(destIdx, destCapacity), status);
+ 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;
+}
+
+//
+// uregex_split The actual API function
+//
+U_CAPI int32_t U_EXPORT2
+uregex_split(URegularExpression *regexp2,
+ UChar *destBuf,
+ int32_t destCapacity,
+ int32_t *requiredCapacity,
+ UChar *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ if (validateRE(regexp, TRUE, status) == FALSE) {
+ return 0;
+ }
+ if ((destBuf == NULL && destCapacity > 0) ||
+ destCapacity < 0 ||
+ destFields == NULL ||
+ destFieldsCapacity < 1 ) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return RegexCImpl::split(regexp, destBuf, destCapacity, requiredCapacity, destFields, destFieldsCapacity, status);
+}
+
+
+//
+// uregex_splitUText...can just use the normal C++ method
+//
+U_CAPI int32_t U_EXPORT2
+uregex_splitUText(URegularExpression *regexp2,
+ UText *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status) {
+ RegularExpression *regexp = (RegularExpression*)regexp2;
+ return regexp->fMatcher->split(regexp->fMatcher->inputText(), destFields, destFieldsCapacity, *status);
+}
+
+
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uregexc.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uregexc.cpp
new file mode 100644
index 00000000000..6590020661e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/usearch.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/usearch.cpp
new file mode 100644
index 00000000000..7078409fc2f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/usearch.cpp
@@ -0,0 +1,4842 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2011 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 07/02/2001 synwee Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/usearch.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "normalizer2impl.h"
+#include "ucol_imp.h"
+#include "usrchimp.h"
+#include "cmemory.h"
+#include "ucln_in.h"
+#include "uassert.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_USE
+
+// don't use Boyer-Moore
+// (and if we decide to turn this on again there are several new TODOs that will need to be addressed)
+#define BOYER_MOORE 0
+
+#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 *fcdTrieIndex = NULL;
+static UChar32 fcdHighStart = 0;
+
+// 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->extendCEs ? ci->extendCEs : ci->CEs;
+ if (ci->flags & UCOL_ITER_INNORMBUF) {
+ ci->flags = ci->origFlags;
+ }
+ ci->fcdPosition = NULL;
+
+ ci->offsetReturn = NULL;
+ ci->offsetStore = ci->offsetBuffer;
+ ci->offsetRepeatCount = ci->offsetRepeatValue = 0;
+}
+
+/**
+* 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) {
+ fcdTrieIndex = 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 (fcdTrieIndex == NULL) {
+ fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, 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)
+{
+ const UChar *temp = str + *offset;
+ uint16_t result = unorm_nextFCD16(fcdTrieIndex, fcdHighStart, temp, str + strlength);
+ *offset = (int32_t)(temp - str);
+ 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;
+ }
+ }
+ } else if (strsrch->strength >= UCOL_QUATERNARY && sourcece == UCOL_IGNORABLE) {
+ sourcece = 0xFFFF;
+ }
+
+ 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;
+}
+
+/**
+* Adds a uint64_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 int64_t * addTouint64_tArray(int64_t *destination,
+ uint32_t offset,
+ uint32_t *destinationlength,
+ uint64_t value,
+ uint32_t increments,
+ UErrorCode *status)
+{
+ uint32_t newlength = *destinationlength;
+ if (offset + 1 == newlength) {
+ newlength += increments;
+ int64_t *temp = (int64_t *)allocateMemory(
+ sizeof(int64_t) * newlength, status);
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ uprv_memcpy(temp, destination, sizeof(int64_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_,
+ status);
+ }
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ 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;
+}
+
+/**
+* Initializing the pce 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 initializePatternPCETable(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ UPattern *pattern = &(strsrch->pattern);
+ uint32_t pcetablesize = INITIAL_ARRAY_SIZE_;
+ int64_t *pcetable = pattern->PCEBuffer;
+ 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_,
+ status);
+ }
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (pattern->PCE != pcetable && pattern->PCE != NULL) {
+ uprv_free(pattern->PCE);
+ }
+
+ uint16_t offset = 0;
+ uint16_t result = 0;
+ int64_t pce;
+
+ uprv_init_pce(coleiter);
+
+ // ** Should processed CEs be signed or unsigned?
+ // ** (the rest of the code in this file seems to play fast-and-loose with
+ // ** whether a CE is signed or unsigned. For example, look at routine above this one.)
+ while ((pce = ucol_nextProcessed(coleiter, NULL, NULL, status)) != UCOL_PROCESSED_NULLORDER &&
+ U_SUCCESS(*status)) {
+ int64_t *temp = addTouint64_tArray(pcetable, offset, &pcetablesize,
+ pce,
+ patternlength - ucol_getOffset(coleiter) + 1,
+ status);
+
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ offset += 1;
+
+ if (pcetable != temp && pcetable != pattern->PCEBuffer) {
+ uprv_free(pcetable);
+ }
+
+ pcetable = temp;
+ //result += (uint16_t)(ucol_getMaxExpansion(coleiter, ce) - 1);
+ }
+
+ pcetable[offset] = 0;
+ pattern->PCE = pcetable;
+ pattern->PCELength = 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_;
+ }
+
+ // ** HACK **
+ if (strsrch->pattern.PCE != NULL) {
+ if (strsrch->pattern.PCE != strsrch->pattern.PCEBuffer) {
+ uprv_free(strsrch->pattern.PCE);
+ }
+
+ strsrch->pattern.PCE = NULL;
+ }
+
+ // 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;
+}
+
+#if BOYER_MOORE
+/**
+* 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;
+}
+#endif // #if BOYER_MOORE
+
+/**
+* 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);
+ }
+}
+
+#if BOYER_MOORE
+/**
+* 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 != (uint32_t)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) || ce == UCOL_NULLORDER) {
+ 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;
+ int32_t ce;
+ setColEIterOffset(coleiter, start);
+ while ((ce = getCE(strsrch, ucol_next(coleiter, &status))) != firstce) {
+ if (U_FAILURE(status) || ce == UCOL_NULLORDER) {
+ 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 ++;
+ }
+
+ 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;
+}
+#endif // #if BOYER_MOORE
+
+/**
+* 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)
+{
+ if (strsrch->strength != UCOL_IDENTICAL) {
+ return TRUE;
+ }
+
+ // Note: We could use Normalizer::compare() or similar, but for short strings
+ // which may not be in FCD it might be faster to just NFD them.
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString t2, p2;
+ strsrch->nfd->normalize(
+ UnicodeString(FALSE, strsrch->search->text + start, end - start), t2, status);
+ strsrch->nfd->normalize(
+ UnicodeString(FALSE, strsrch->pattern.text, strsrch->pattern.textLength), p2, status);
+ // return FALSE if NFD failed
+ return U_SUCCESS(status) && t2 == p2;
+}
+
+#if BOYER_MOORE
+/**
+* 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 (FALSE && !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;
+}
+#endif // #if BOYER_MOORE
+
+// 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);
+
+ result->nfd = Normalizer2Factory::getNFDInstance(*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->pattern.PCE = NULL;
+
+ result->search->breakIter = breakiter;
+#if !UCONFIG_NO_BREAK_ITERATION
+ result->search->internalBreakIter = ubrk_open(UBRK_CHARACTER, ucol_getLocaleByType(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->utilIter = NULL;
+ result->textIter = ucol_openElements(collator, text,
+ textlength, status);
+ if (U_FAILURE(*status)) {
+ usearch_close(result);
+ return NULL;
+ }
+
+ result->search->isOverlap = FALSE;
+ result->search->isCanonicalMatch = FALSE;
+ result->search->elementComparisonType = 0;
+ 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);
+ }
+
+ if (strsrch->pattern.PCE != NULL &&
+ strsrch->pattern.PCE != strsrch->pattern.PCEBuffer) {
+ uprv_free(strsrch->pattern.PCE);
+ }
+
+ ucol_closeElements(strsrch->textIter);
+ ucol_closeElements(strsrch->utilIter);
+
+ if (strsrch->ownCollator && strsrch->collator) {
+ ucol_close((UCollator *)strsrch->collator);
+ }
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (strsrch->search->internalBreakIter) {
+ ubrk_close(strsrch->search->internalBreakIter);
+ }
+#endif
+
+ 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_ELEMENT_COMPARISON :
+ if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
+ strsrch->search->elementComparisonType = (int16_t)value;
+ } else {
+ strsrch->search->elementComparisonType = 0;
+ }
+ 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_ELEMENT_COMPARISON :
+ {
+ int16_t value = strsrch->search->elementComparisonType;
+ if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
+ return (USearchAttributeValue)value;
+ } else {
+ return USEARCH_STANDARD_ELEMENT_COMPARISON;
+ }
+ }
+ 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_getLocaleByType(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)) {
+ /* free offset buffer to avoid memory leak before initializing. */
+ ucol_freeOffsetBuffer(&(strsrch->textIter->iteratordata_));
+ uprv_init_collIterate(collator, strsrch->search->text,
+ strsrch->search->textLength,
+ &(strsrch->textIter->iteratordata_),
+ status);
+ strsrch->utilIter->iteratordata_.coll = collator;
+ }
+ }
+ }
+
+ // **** are these calls needed?
+ // **** we call uprv_init_pce in initializePatternPCETable
+ // **** and the CEBuffer constructor...
+#if 0
+ uprv_init_pce(strsrch->textIter);
+ uprv_init_pce(strsrch->utilIter);
+#endif
+ }
+}
+
+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 BOYER_MOORE
+ 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
+ if (offset == textlength ||
+ (! search->isOverlap &&
+ (search->matchedIndex != USEARCH_DONE &&
+ offset + search->matchedLength > textlength))) {
+ // not enough characters to match
+ setMatchNotFound(strsrch);
+ return USEARCH_DONE;
+ }
+#endif
+ }
+ 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;
+ }
+
+#if !BOYER_MOORE
+ if (search->matchedIndex == USEARCH_DONE) {
+ ucol_setOffset(strsrch->textIter, search->textLength, status);
+ } else {
+ ucol_setOffset(strsrch->textIter, search->matchedIndex, status);
+ }
+#endif
+
+ 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 BOYER_MOORE
+ 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;
+ }
+#else
+ // Could check pattern length, but the
+ // linear search will do the right thing
+ if (offset == 0 || matchedindex == 0) {
+ setMatchNotFound(strsrch);
+ return USEARCH_DONE;
+ }
+#endif
+ }
+
+ 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;
+
+ // **** hack to deal w/ how processed CEs encode quaternary ****
+ UCollationStrength newStrength = ucol_getStrength(strsrch->collator);
+ if ((strsrch->strength < UCOL_QUATERNARY && newStrength >= UCOL_QUATERNARY) ||
+ (strsrch->strength >= UCOL_QUATERNARY && newStrength < UCOL_QUATERNARY)) {
+ sameCollAttribute = FALSE;
+ }
+
+ 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);
+ }
+ /* free offset buffer to avoid memory leak before initializing. */
+ ucol_freeOffsetBuffer(&(strsrch->textIter->iteratordata_));
+ uprv_init_collIterate(strsrch->collator, strsrch->search->text,
+ strsrch->search->textLength,
+ &(strsrch->textIter->iteratordata_),
+ &status);
+ strsrch->search->matchedLength = 0;
+ strsrch->search->matchedIndex = USEARCH_DONE;
+ strsrch->search->isOverlap = FALSE;
+ strsrch->search->isCanonicalMatch = FALSE;
+ strsrch->search->elementComparisonType = 0;
+ strsrch->search->isForwardSearching = TRUE;
+ strsrch->search->reset = TRUE;
+ }
+}
+
+//
+// CEI Collation Element + source text index.
+// These structs are kept in the circular buffer.
+//
+struct CEI {
+ int64_t ce;
+ int32_t lowIndex;
+ int32_t highIndex;
+};
+
+U_NAMESPACE_BEGIN
+
+
+//
+// CEBuffer A circular buffer of CEs from the text being searched.
+//
+#define DEFAULT_CEBUFFER_SIZE 96
+#define CEBUFFER_EXTRA 32
+// Some typical max values to make buffer size more reasonable for asymmetric search.
+// #8694 is for a better long-term solution to allocation of this buffer.
+#define MAX_TARGET_IGNORABLES_PER_PAT_JAMO_L 8
+#define MAX_TARGET_IGNORABLES_PER_PAT_OTHER 3
+#define MIGHT_BE_JAMO_L(c) ((c >= 0x1100 && c <= 0x115E) || (c >= 0x3131 && c <= 0x314E) || (c >= 0x3165 && c <= 0x3186))
+struct CEBuffer {
+ CEI defBuf[DEFAULT_CEBUFFER_SIZE];
+ CEI *buf;
+ int32_t bufSize;
+ int32_t firstIx;
+ int32_t limitIx;
+ UCollationElements *ceIter;
+ UStringSearch *strSearch;
+
+
+
+ CEBuffer(UStringSearch *ss, UErrorCode *status);
+ ~CEBuffer();
+ const CEI *get(int32_t index);
+ const CEI *getPrevious(int32_t index);
+};
+
+
+CEBuffer::CEBuffer(UStringSearch *ss, UErrorCode *status) {
+ buf = defBuf;
+ strSearch = ss;
+ bufSize = ss->pattern.PCELength + CEBUFFER_EXTRA;
+ if (ss->search->elementComparisonType != 0) {
+ const UChar * patText = ss->pattern.text;
+ if (patText) {
+ const UChar * patTextLimit = patText + ss->pattern.textLength;
+ while ( patText < patTextLimit ) {
+ UChar c = *patText++;
+ if (MIGHT_BE_JAMO_L(c)) {
+ bufSize += MAX_TARGET_IGNORABLES_PER_PAT_JAMO_L;
+ } else {
+ // No check for surrogates, we might allocate slightly more buffer than necessary.
+ bufSize += MAX_TARGET_IGNORABLES_PER_PAT_OTHER;
+ }
+ }
+ }
+ }
+ ceIter = ss->textIter;
+ firstIx = 0;
+ limitIx = 0;
+
+ uprv_init_pce(ceIter);
+
+ if (bufSize>DEFAULT_CEBUFFER_SIZE) {
+ buf = (CEI *)uprv_malloc(bufSize * sizeof(CEI));
+ if (buf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+}
+
+// TODO: add a reset or init function so that allocated
+// buffers can be retained & reused.
+
+CEBuffer::~CEBuffer() {
+ if (buf != defBuf) {
+ uprv_free(buf);
+ }
+}
+
+
+// Get the CE with the specified index.
+// Index must be in the range
+// n-history_size < index < n+1
+// where n is the largest index to have been fetched by some previous call to this function.
+// The CE value will be UCOL__PROCESSED_NULLORDER at end of input.
+//
+const CEI *CEBuffer::get(int32_t index) {
+ int i = index % bufSize;
+
+ if (index>=firstIx && index<limitIx) {
+ // The request was for an entry already in our buffer.
+ // Just return it.
+ return &buf[i];
+ }
+
+ // Caller is requesting a new, never accessed before, CE.
+ // Verify that it is the next one in sequence, which is all
+ // that is allowed.
+ if (index != limitIx) {
+ U_ASSERT(FALSE);
+
+ return NULL;
+ }
+
+ // Manage the circular CE buffer indexing
+ limitIx++;
+
+ if (limitIx - firstIx >= bufSize) {
+ // The buffer is full, knock out the lowest-indexed entry.
+ firstIx++;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ buf[i].ce = ucol_nextProcessed(ceIter, &buf[i].lowIndex, &buf[i].highIndex, &status);
+
+ return &buf[i];
+}
+
+// Get the CE with the specified index.
+// Index must be in the range
+// n-history_size < index < n+1
+// where n is the largest index to have been fetched by some previous call to this function.
+// The CE value will be UCOL__PROCESSED_NULLORDER at end of input.
+//
+const CEI *CEBuffer::getPrevious(int32_t index) {
+ int i = index % bufSize;
+
+ if (index>=firstIx && index<limitIx) {
+ // The request was for an entry already in our buffer.
+ // Just return it.
+ return &buf[i];
+ }
+
+ // Caller is requesting a new, never accessed before, CE.
+ // Verify that it is the next one in sequence, which is all
+ // that is allowed.
+ if (index != limitIx) {
+ U_ASSERT(FALSE);
+
+ return NULL;
+ }
+
+ // Manage the circular CE buffer indexing
+ limitIx++;
+
+ if (limitIx - firstIx >= bufSize) {
+ // The buffer is full, knock out the lowest-indexed entry.
+ firstIx++;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ buf[i].ce = ucol_previousProcessed(ceIter, &buf[i].lowIndex, &buf[i].highIndex, &status);
+
+ return &buf[i];
+}
+
+U_NAMESPACE_END
+
+
+// #define USEARCH_DEBUG
+
+#ifdef USEARCH_DEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+/*
+ * Find the next break boundary after startIndex. If the UStringSearch object
+ * has an external break iterator, use that. Otherwise use the internal character
+ * break iterator.
+ */
+static int32_t nextBoundaryAfter(UStringSearch *strsrch, int32_t startIndex) {
+#if 0
+ const UChar *text = strsrch->search->text;
+ int32_t textLen = strsrch->search->textLength;
+
+ U_ASSERT(startIndex>=0);
+ U_ASSERT(startIndex<=textLen);
+
+ if (startIndex >= textLen) {
+ return startIndex;
+ }
+
+ UChar32 c;
+ int32_t i = startIndex;
+ U16_NEXT(text, i, textLen, c);
+
+ // If we are on a control character, stop without looking for combining marks.
+ // Control characters do not combine.
+ int32_t gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
+ if (gcProperty==U_GCB_CONTROL || gcProperty==U_GCB_LF || gcProperty==U_GCB_CR) {
+ return i;
+ }
+
+ // The initial character was not a control, and can thus accept trailing
+ // combining characters. Advance over however many of them there are.
+ int32_t indexOfLastCharChecked;
+ for (;;) {
+ indexOfLastCharChecked = i;
+ if (i>=textLen) {
+ break;
+ }
+ U16_NEXT(text, i, textLen, c);
+ gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
+ if (gcProperty != U_GCB_EXTEND && gcProperty != U_GCB_SPACING_MARK) {
+ break;
+ }
+ }
+ return indexOfLastCharChecked;
+#elif !UCONFIG_NO_BREAK_ITERATION
+ UBreakIterator *breakiterator = strsrch->search->breakIter;
+
+ if (breakiterator == NULL) {
+ breakiterator = strsrch->search->internalBreakIter;
+ }
+
+ if (breakiterator != NULL) {
+ return ubrk_following(breakiterator, startIndex);
+ }
+
+ return startIndex;
+#else
+ // **** or should we use the original code? ****
+ return startIndex;
+#endif
+
+}
+
+/*
+ * Returns TRUE if index is on a break boundary. If the UStringSearch
+ * has an external break iterator, test using that, otherwise test
+ * using the internal character break iterator.
+ */
+static UBool isBreakBoundary(UStringSearch *strsrch, int32_t index) {
+#if 0
+ const UChar *text = strsrch->search->text;
+ int32_t textLen = strsrch->search->textLength;
+
+ U_ASSERT(index>=0);
+ U_ASSERT(index<=textLen);
+
+ if (index>=textLen || index<=0) {
+ return TRUE;
+ }
+
+ // If the character at the current index is not a GRAPHEME_EXTEND
+ // then we can not be within a combining sequence.
+ UChar32 c;
+ U16_GET(text, 0, index, textLen, c);
+ int32_t gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
+ if (gcProperty != U_GCB_EXTEND && gcProperty != U_GCB_SPACING_MARK) {
+ return TRUE;
+ }
+
+ // We are at a combining mark. If the preceding character is anything
+ // except a CONTROL, CR or LF, we are in a combining sequence.
+ U16_PREV(text, 0, index, c);
+ gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
+ UBool combining = !(gcProperty==U_GCB_CONTROL || gcProperty==U_GCB_LF || gcProperty==U_GCB_CR);
+ return !combining;
+#elif !UCONFIG_NO_BREAK_ITERATION
+ UBreakIterator *breakiterator = strsrch->search->breakIter;
+
+ if (breakiterator == NULL) {
+ breakiterator = strsrch->search->internalBreakIter;
+ }
+
+ return (breakiterator != NULL && ubrk_isBoundary(breakiterator, index));
+#else
+ // **** or use the original code? ****
+ return TRUE;
+#endif
+}
+
+#if 0
+static UBool onBreakBoundaries(const UStringSearch *strsrch, int32_t start, int32_t end)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ UBreakIterator *breakiterator = strsrch->search->breakIter;
+
+ if (breakiterator != NULL) {
+ 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;
+ }
+
+ return ubrk_isBoundary(breakiterator, start) &&
+ ubrk_isBoundary(breakiterator, end);
+ }
+#endif
+
+ return TRUE;
+}
+#endif
+
+typedef enum {
+ U_CE_MATCH = -1,
+ U_CE_NO_MATCH = 0,
+ U_CE_SKIP_TARG,
+ U_CE_SKIP_PATN
+} UCompareCEsResult;
+#define U_CE_LEVEL2_BASE 0x00000005
+#define U_CE_LEVEL3_BASE 0x00050000
+
+static UCompareCEsResult compareCE64s(int64_t targCE, int64_t patCE, int16_t compareType) {
+ if (targCE == patCE) {
+ return U_CE_MATCH;
+ }
+ if (compareType == 0) {
+ return U_CE_NO_MATCH;
+ }
+
+ int64_t targCEshifted = targCE >> 32;
+ int64_t patCEshifted = patCE >> 32;
+ int64_t mask;
+
+ mask = 0xFFFF0000;
+ int32_t targLev1 = (int32_t)(targCEshifted & mask);
+ int32_t patLev1 = (int32_t)(patCEshifted & mask);
+ if ( targLev1 != patLev1 ) {
+ if ( targLev1 == 0 ) {
+ return U_CE_SKIP_TARG;
+ }
+ if ( patLev1 == 0 && compareType == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD ) {
+ return U_CE_SKIP_PATN;
+ }
+ return U_CE_NO_MATCH;
+ }
+
+ mask = 0x0000FFFF;
+ int32_t targLev2 = (int32_t)(targCEshifted & mask);
+ int32_t patLev2 = (int32_t)(patCEshifted & mask);
+ if ( targLev2 != patLev2 ) {
+ if ( targLev2 == 0 ) {
+ return U_CE_SKIP_TARG;
+ }
+ if ( patLev2 == 0 && compareType == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD ) {
+ return U_CE_SKIP_PATN;
+ }
+ return (patLev2 == U_CE_LEVEL2_BASE || (compareType == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD && targLev2 == U_CE_LEVEL2_BASE) )?
+ U_CE_MATCH: U_CE_NO_MATCH;
+ }
+
+ mask = 0xFFFF0000;
+ int32_t targLev3 = (int32_t)(targCE & mask);
+ int32_t patLev3 = (int32_t)(patCE & mask);
+ if ( targLev3 != patLev3 ) {
+ return (patLev3 == U_CE_LEVEL3_BASE || (compareType == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD && targLev3 == U_CE_LEVEL3_BASE) )?
+ U_CE_MATCH: U_CE_NO_MATCH;
+ }
+
+ return U_CE_MATCH;
+}
+
+#if BOYER_MOORE
+// TODO: #if BOYER_MOORE, need 32-bit version of compareCE64s
+#endif
+
+U_CAPI UBool U_EXPORT2 usearch_search(UStringSearch *strsrch,
+ int32_t startIdx,
+ int32_t *matchStart,
+ int32_t *matchLimit,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+
+ // TODO: reject search patterns beginning with a combining char.
+
+#ifdef USEARCH_DEBUG
+ if (getenv("USEARCH_DEBUG") != NULL) {
+ printf("Pattern CEs\n");
+ for (int ii=0; ii<strsrch->pattern.CELength; ii++) {
+ printf(" %8x", strsrch->pattern.CE[ii]);
+ }
+ printf("\n");
+ }
+
+#endif
+ // Input parameter sanity check.
+ // TODO: should input indicies clip to the text length
+ // in the same way that UText does.
+ if(strsrch->pattern.CELength == 0 ||
+ startIdx < 0 ||
+ startIdx > strsrch->search->textLength ||
+ strsrch->pattern.CE == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+
+ if (strsrch->pattern.PCE == NULL) {
+ initializePatternPCETable(strsrch, status);
+ }
+
+ ucol_setOffset(strsrch->textIter, startIdx, status);
+ CEBuffer ceb(strsrch, status);
+
+
+ int32_t targetIx = 0;
+ const CEI *targetCEI = NULL;
+ int32_t patIx;
+ UBool found;
+
+ int32_t mStart = -1;
+ int32_t mLimit = -1;
+ int32_t minLimit;
+ int32_t maxLimit;
+
+
+
+ // Outer loop moves over match starting positions in the
+ // target CE space.
+ // Here we see the target as a sequence of collation elements, resulting from the following:
+ // 1. Target characters were decomposed, and (if appropriate) other compressions and expansions are applied
+ // (for example, digraphs such as IJ may be broken into two characters).
+ // 2. An int64_t CE weight is determined for each resulting unit (high 16 bits are primary strength, next
+ // 16 bits are secondary, next 16 (the high 16 bits of the low 32-bit half) are tertiary. Any of these
+ // fields that are for strengths below that of the collator are set to 0. If this makes the int64_t
+ // CE weight 0 (as for a combining diacritic with secondary weight when the collator strentgh is primary),
+ // then the CE is deleted, so the following code sees only CEs that are relevant.
+ // For each CE, the lowIndex and highIndex correspond to where this CE begins and ends in the original text.
+ // If lowIndex==highIndex, either the CE resulted from an expansion/decomposition of one of the original text
+ // characters, or the CE marks the limit of the target text (in which case the CE weight is UCOL_PROCESSED_NULLORDER).
+ //
+ for(targetIx=0; ; targetIx++)
+ {
+ found = TRUE;
+ // Inner loop checks for a match beginning at each
+ // position from the outer loop.
+ int32_t targetIxOffset = 0;
+ int64_t patCE = 0;
+ // For targetIx > 0, this ceb.get gets a CE that is as far back in the ring buffer
+ // (compared to the last CE fetched for the previous targetIx value) as we need to go
+ // for this targetIx value, so if it is non-NULL then other ceb.get calls should be OK.
+ const CEI *firstCEI = ceb.get(targetIx);
+ if (firstCEI == NULL) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ found = FALSE;
+ break;
+ }
+
+ for (patIx=0; patIx<strsrch->pattern.PCELength; patIx++) {
+ patCE = strsrch->pattern.PCE[patIx];
+ targetCEI = ceb.get(targetIx+patIx+targetIxOffset);
+ // Compare CE from target string with CE from the pattern.
+ // Note that the target CE will be UCOL_PROCESSED_NULLORDER if we reach the end of input,
+ // which will fail the compare, below.
+ UCompareCEsResult ceMatch = compareCE64s(targetCEI->ce, patCE, strsrch->search->elementComparisonType);
+ if ( ceMatch == U_CE_NO_MATCH ) {
+ found = FALSE;
+ break;
+ } else if ( ceMatch > U_CE_NO_MATCH ) {
+ if ( ceMatch == U_CE_SKIP_TARG ) {
+ // redo with same patCE, next targCE
+ patIx--;
+ targetIxOffset++;
+ } else { // ceMatch == U_CE_SKIP_PATN
+ // redo with same targCE, next patCE
+ targetIxOffset--;
+ }
+ }
+ }
+ targetIxOffset += strsrch->pattern.PCELength; // this is now the offset in target CE space to end of the match so far
+
+ if (!found && ((targetCEI == NULL) || (targetCEI->ce != UCOL_PROCESSED_NULLORDER))) {
+ // No match at this targetIx. Try again at the next.
+ continue;
+ }
+
+ if (!found) {
+ // No match at all, we have run off the end of the target text.
+ break;
+ }
+
+
+ // We have found a match in CE space.
+ // Now determine the bounds in string index space.
+ // There still is a chance of match failure if the CE range not correspond to
+ // an acceptable character range.
+ //
+ const CEI *lastCEI = ceb.get(targetIx + targetIxOffset - 1);
+
+ mStart = firstCEI->lowIndex;
+ minLimit = lastCEI->lowIndex;
+
+ // Look at the CE following the match. If it is UCOL_NULLORDER the match
+ // extended to the end of input, and the match is good.
+
+ // Look at the high and low indices of the CE following the match. If
+ // they are the same it means one of two things:
+ // 1. The match extended to the last CE from the target text, which is OK, or
+ // 2. The last CE that was part of the match is in an expansion that extends
+ // to the first CE after the match. In this case, we reject the match.
+ const CEI *nextCEI = 0;
+ if (strsrch->search->elementComparisonType == 0) {
+ nextCEI = ceb.get(targetIx + targetIxOffset);
+ maxLimit = nextCEI->lowIndex;
+ if (nextCEI->lowIndex == nextCEI->highIndex && nextCEI->ce != UCOL_PROCESSED_NULLORDER) {
+ found = FALSE;
+ }
+ } else {
+ for ( ; ; ++targetIxOffset ) {
+ nextCEI = ceb.get(targetIx + targetIxOffset);
+ maxLimit = nextCEI->lowIndex;
+ // If we are at the end of the target too, match succeeds
+ if ( nextCEI->ce == UCOL_PROCESSED_NULLORDER ) {
+ break;
+ }
+ // As long as the next CE has primary weight of 0,
+ // it is part of the last target element matched by the pattern;
+ // make sure it can be part of a match with the last patCE
+ if ( (((nextCEI->ce) >> 32) & 0xFFFF0000UL) == 0 ) {
+ UCompareCEsResult ceMatch = compareCE64s(nextCEI->ce, patCE, strsrch->search->elementComparisonType);
+ if ( ceMatch == U_CE_NO_MATCH || ceMatch == U_CE_SKIP_PATN ) {
+ found = FALSE;
+ break;
+ }
+ // If lowIndex == highIndex, this target CE is part of an expansion of the last matched
+ // target element, but it has non-zero primary weight => match fails
+ } else if ( nextCEI->lowIndex == nextCEI->highIndex ) {
+ found = false;
+ break;
+ // Else the target CE is not part of an expansion of the last matched element, match succeeds
+ } else {
+ break;
+ }
+ }
+ }
+
+
+ // Check for the start of the match being within a combining sequence.
+ // This can happen if the pattern itself begins with a combining char, and
+ // the match found combining marks in the target text that were attached
+ // to something else.
+ // This type of match should be rejected for not completely consuming a
+ // combining sequence.
+ if (!isBreakBoundary(strsrch, mStart)) {
+ found = FALSE;
+ }
+
+ // Check for the start of the match being within an Collation Element Expansion,
+ // meaning that the first char of the match is only partially matched.
+ // With exapnsions, the first CE will report the index of the source
+ // character, and all subsequent (expansions) CEs will report the source index of the
+ // _following_ character.
+ int32_t secondIx = firstCEI->highIndex;
+ if (mStart == secondIx) {
+ found = FALSE;
+ }
+
+ // Advance the match end position to the first acceptable match boundary.
+ // This advances the index over any combining charcters.
+ mLimit = maxLimit;
+ if (minLimit < maxLimit) {
+ // When the last CE's low index is same with its high index, the CE is likely
+ // a part of expansion. In this case, the index is located just after the
+ // character corresponding to the CEs compared above. If the index is right
+ // at the break boundary, move the position to the next boundary will result
+ // incorrect match length when there are ignorable characters exist between
+ // the position and the next character produces CE(s). See ticket#8482.
+ if (minLimit == lastCEI->highIndex && isBreakBoundary(strsrch, minLimit)) {
+ mLimit = minLimit;
+ } else {
+ int32_t nba = nextBoundaryAfter(strsrch, minLimit);
+ if (nba >= lastCEI->highIndex) {
+ mLimit = nba;
+ }
+ }
+ }
+
+ #ifdef USEARCH_DEBUG
+ if (getenv("USEARCH_DEBUG") != NULL) {
+ printf("minLimit, maxLimit, mLimit = %d, %d, %d\n", minLimit, maxLimit, mLimit);
+ }
+ #endif
+
+ // If advancing to the end of a combining sequence in character indexing space
+ // advanced us beyond the end of the match in CE space, reject this match.
+ if (mLimit > maxLimit) {
+ found = FALSE;
+ }
+
+ if (!isBreakBoundary(strsrch, mLimit)) {
+ found = FALSE;
+ }
+
+ if (! checkIdentical(strsrch, mStart, mLimit)) {
+ found = FALSE;
+ }
+
+ if (found) {
+ break;
+ }
+ }
+
+ #ifdef USEARCH_DEBUG
+ if (getenv("USEARCH_DEBUG") != NULL) {
+ printf("Target CEs [%d .. %d]\n", ceb.firstIx, ceb.limitIx);
+ int32_t lastToPrint = ceb.limitIx+2;
+ for (int ii=ceb.firstIx; ii<lastToPrint; ii++) {
+ printf("%8x@%d ", ceb.get(ii)->ce, ceb.get(ii)->srcIndex);
+ }
+ printf("\n%s\n", found? "match found" : "no match");
+ }
+ #endif
+
+ // All Done. Store back the match bounds to the caller.
+ //
+ if (found==FALSE) {
+ mLimit = -1;
+ mStart = -1;
+ }
+
+ if (matchStart != NULL) {
+ *matchStart= mStart;
+ }
+
+ if (matchLimit != NULL) {
+ *matchLimit = mLimit;
+ }
+
+ return found;
+}
+
+U_CAPI UBool U_EXPORT2 usearch_searchBackwards(UStringSearch *strsrch,
+ int32_t startIdx,
+ int32_t *matchStart,
+ int32_t *matchLimit,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+
+ // TODO: reject search patterns beginning with a combining char.
+
+#ifdef USEARCH_DEBUG
+ if (getenv("USEARCH_DEBUG") != NULL) {
+ printf("Pattern CEs\n");
+ for (int ii=0; ii<strsrch->pattern.CELength; ii++) {
+ printf(" %8x", strsrch->pattern.CE[ii]);
+ }
+ printf("\n");
+ }
+
+#endif
+ // Input parameter sanity check.
+ // TODO: should input indicies clip to the text length
+ // in the same way that UText does.
+ if(strsrch->pattern.CELength == 0 ||
+ startIdx < 0 ||
+ startIdx > strsrch->search->textLength ||
+ strsrch->pattern.CE == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+
+ if (strsrch->pattern.PCE == NULL) {
+ initializePatternPCETable(strsrch, status);
+ }
+
+ CEBuffer ceb(strsrch, status);
+ int32_t targetIx = 0;
+
+ /*
+ * Pre-load the buffer with the CE's for the grapheme
+ * after our starting position so that we're sure that
+ * we can look at the CE following the match when we
+ * check the match boundaries.
+ *
+ * This will also pre-fetch the first CE that we'll
+ * consider for the match.
+ */
+ if (startIdx < strsrch->search->textLength) {
+ UBreakIterator *bi = strsrch->search->internalBreakIter;
+ int32_t next = ubrk_following(bi, startIdx);
+
+ ucol_setOffset(strsrch->textIter, next, status);
+
+ for (targetIx = 0; ; targetIx += 1) {
+ if (ceb.getPrevious(targetIx)->lowIndex < startIdx) {
+ break;
+ }
+ }
+ } else {
+ ucol_setOffset(strsrch->textIter, startIdx, status);
+ }
+
+
+ const CEI *targetCEI = NULL;
+ int32_t patIx;
+ UBool found;
+
+ int32_t limitIx = targetIx;
+ int32_t mStart = -1;
+ int32_t mLimit = -1;
+ int32_t minLimit;
+ int32_t maxLimit;
+
+
+
+ // Outer loop moves over match starting positions in the
+ // target CE space.
+ // Here, targetIx values increase toward the beginning of the base text (i.e. we get the text CEs in reverse order).
+ // But patIx is 0 at the beginning of the pattern and increases toward the end.
+ // So this loop performs a comparison starting with the end of pattern, and prcessd toward the beginning of the pattern
+ // and the beginning of the base text.
+ for(targetIx = limitIx; ; targetIx += 1)
+ {
+ found = TRUE;
+ // For targetIx > limitIx, this ceb.getPrevious gets a CE that is as far back in the ring buffer
+ // (compared to the last CE fetched for the previous targetIx value) as we need to go
+ // for this targetIx value, so if it is non-NULL then other ceb.getPrevious calls should be OK.
+ const CEI *lastCEI = ceb.getPrevious(targetIx);
+ if (lastCEI == NULL) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ found = FALSE;
+ break;
+ }
+ // Inner loop checks for a match beginning at each
+ // position from the outer loop.
+ int32_t targetIxOffset = 0;
+ for (patIx = strsrch->pattern.PCELength - 1; patIx >= 0; patIx -= 1) {
+ int64_t patCE = strsrch->pattern.PCE[patIx];
+
+ targetCEI = ceb.getPrevious(targetIx + strsrch->pattern.PCELength - 1 - patIx + targetIxOffset);
+ // Compare CE from target string with CE from the pattern.
+ // Note that the target CE will be UCOL_NULLORDER if we reach the end of input,
+ // which will fail the compare, below.
+ UCompareCEsResult ceMatch = compareCE64s(targetCEI->ce, patCE, strsrch->search->elementComparisonType);
+ if ( ceMatch == U_CE_NO_MATCH ) {
+ found = FALSE;
+ break;
+ } else if ( ceMatch > U_CE_NO_MATCH ) {
+ if ( ceMatch == U_CE_SKIP_TARG ) {
+ // redo with same patCE, next targCE
+ patIx++;
+ targetIxOffset++;
+ } else { // ceMatch == U_CE_SKIP_PATN
+ // redo with same targCE, next patCE
+ targetIxOffset--;
+ }
+ }
+ }
+
+ if (!found && ((targetCEI == NULL) || (targetCEI->ce != UCOL_PROCESSED_NULLORDER))) {
+ // No match at this targetIx. Try again at the next.
+ continue;
+ }
+
+ if (!found) {
+ // No match at all, we have run off the end of the target text.
+ break;
+ }
+
+
+ // We have found a match in CE space.
+ // Now determine the bounds in string index space.
+ // There still is a chance of match failure if the CE range not correspond to
+ // an acceptable character range.
+ //
+ const CEI *firstCEI = ceb.getPrevious(targetIx + strsrch->pattern.PCELength - 1 + targetIxOffset);
+ mStart = firstCEI->lowIndex;
+
+ // Check for the start of the match being within a combining sequence.
+ // This can happen if the pattern itself begins with a combining char, and
+ // the match found combining marks in the target text that were attached
+ // to something else.
+ // This type of match should be rejected for not completely consuming a
+ // combining sequence.
+ if (!isBreakBoundary(strsrch, mStart)) {
+ found = FALSE;
+ }
+
+ // Look at the high index of the first CE in the match. If it's the same as the
+ // low index, the first CE in the match is in the middle of an expansion.
+ if (mStart == firstCEI->highIndex) {
+ found = FALSE;
+ }
+
+
+ minLimit = lastCEI->lowIndex;
+
+ if (targetIx > 0) {
+ // Look at the CE following the match. If it is UCOL_NULLORDER the match
+ // extended to the end of input, and the match is good.
+
+ // Look at the high and low indices of the CE following the match. If
+ // they are the same it means one of two things:
+ // 1. The match extended to the last CE from the target text, which is OK, or
+ // 2. The last CE that was part of the match is in an expansion that extends
+ // to the first CE after the match. In this case, we reject the match.
+ const CEI *nextCEI = ceb.getPrevious(targetIx - 1);
+
+ if (nextCEI->lowIndex == nextCEI->highIndex && nextCEI->ce != UCOL_PROCESSED_NULLORDER) {
+ found = FALSE;
+ }
+
+ mLimit = maxLimit = nextCEI->lowIndex;
+
+ // Advance the match end position to the first acceptable match boundary.
+ // This advances the index over any combining charcters.
+ if (minLimit < maxLimit) {
+ int32_t nba = nextBoundaryAfter(strsrch, minLimit);
+
+ if (nba >= lastCEI->highIndex) {
+ mLimit = nba;
+ }
+ }
+
+ // If advancing to the end of a combining sequence in character indexing space
+ // advanced us beyond the end of the match in CE space, reject this match.
+ if (mLimit > maxLimit) {
+ found = FALSE;
+ }
+
+ // Make sure the end of the match is on a break boundary
+ if (!isBreakBoundary(strsrch, mLimit)) {
+ found = FALSE;
+ }
+
+ } else {
+ // No non-ignorable CEs after this point.
+ // The maximum position is detected by boundary after
+ // the last non-ignorable CE. Combining sequence
+ // across the start index will be truncated.
+ int32_t nba = nextBoundaryAfter(strsrch, minLimit);
+ mLimit = maxLimit = (nba > 0) && (startIdx > nba) ? nba : startIdx;
+ }
+
+ #ifdef USEARCH_DEBUG
+ if (getenv("USEARCH_DEBUG") != NULL) {
+ printf("minLimit, maxLimit, mLimit = %d, %d, %d\n", minLimit, maxLimit, mLimit);
+ }
+ #endif
+
+
+ if (! checkIdentical(strsrch, mStart, mLimit)) {
+ found = FALSE;
+ }
+
+ if (found) {
+ break;
+ }
+ }
+
+ #ifdef USEARCH_DEBUG
+ if (getenv("USEARCH_DEBUG") != NULL) {
+ printf("Target CEs [%d .. %d]\n", ceb.firstIx, ceb.limitIx);
+ int32_t lastToPrint = ceb.limitIx+2;
+ for (int ii=ceb.firstIx; ii<lastToPrint; ii++) {
+ printf("%8x@%d ", ceb.get(ii)->ce, ceb.get(ii)->srcIndex);
+ }
+ printf("\n%s\n", found? "match found" : "no match");
+ }
+ #endif
+
+ // All Done. Store back the match bounds to the caller.
+ //
+ if (found==FALSE) {
+ mLimit = -1;
+ mStart = -1;
+ }
+
+ if (matchStart != NULL) {
+ *matchStart= mStart;
+ }
+
+ if (matchLimit != NULL) {
+ *matchLimit = mLimit;
+ }
+
+ return found;
+}
+
+// internal use methods declared in usrchimp.h -----------------------------
+
+UBool usearch_handleNextExact(UStringSearch *strsrch, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+#if BOYER_MOORE
+ 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;
+ }
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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 --;
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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;
+#else
+ int32_t textOffset = ucol_getOffset(strsrch->textIter);
+ int32_t start = -1;
+ int32_t end = -1;
+
+ if (usearch_search(strsrch, textOffset, &start, &end, status)) {
+ strsrch->search->matchedIndex = start;
+ strsrch->search->matchedLength = end - start;
+ return TRUE;
+ } else {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+#endif
+}
+
+UBool usearch_handleNextCanonical(UStringSearch *strsrch, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+#if BOYER_MOORE
+ 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;
+ }
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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 --;
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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;
+#else
+ int32_t textOffset = ucol_getOffset(strsrch->textIter);
+ int32_t start = -1;
+ int32_t end = -1;
+
+ if (usearch_search(strsrch, textOffset, &start, &end, status)) {
+ strsrch->search->matchedIndex = start;
+ strsrch->search->matchedLength = end - start;
+ return TRUE;
+ } else {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+#endif
+}
+
+UBool usearch_handlePreviousExact(UStringSearch *strsrch, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+#if BOYER_MOORE
+ 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;
+ }
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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;
+ }
+
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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;
+#else
+ int32_t textOffset;
+
+ if (strsrch->search->isOverlap) {
+ if (strsrch->search->matchedIndex != USEARCH_DONE) {
+ textOffset = strsrch->search->matchedIndex + strsrch->search->matchedLength - 1;
+ } else {
+ // move the start position at the end of possible match
+ initializePatternPCETable(strsrch, status);
+ for (int32_t nPCEs = 0; nPCEs < strsrch->pattern.PCELength - 1; nPCEs++) {
+ int64_t pce = ucol_nextProcessed(strsrch->textIter, NULL, NULL, status);
+ if (pce == UCOL_PROCESSED_NULLORDER) {
+ // at the end of the text
+ break;
+ }
+ }
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+ textOffset = ucol_getOffset(strsrch->textIter);
+ }
+ } else {
+ textOffset = ucol_getOffset(strsrch->textIter);
+ }
+
+ int32_t start = -1;
+ int32_t end = -1;
+
+ if (usearch_searchBackwards(strsrch, textOffset, &start, &end, status)) {
+ strsrch->search->matchedIndex = start;
+ strsrch->search->matchedLength = end - start;
+ return TRUE;
+ } else {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+#endif
+}
+
+UBool usearch_handlePreviousCanonical(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+#if BOYER_MOORE
+ 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;
+ }
+
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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;
+ }
+
+ // TODO: #if BOYER_MOORE, replace with code using 32-bit version of compareCE64s
+ 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;
+#else
+ int32_t textOffset;
+
+ if (strsrch->search->isOverlap) {
+ if (strsrch->search->matchedIndex != USEARCH_DONE) {
+ textOffset = strsrch->search->matchedIndex + strsrch->search->matchedLength - 1;
+ } else {
+ // move the start position at the end of possible match
+ initializePatternPCETable(strsrch, status);
+ for (int32_t nPCEs = 0; nPCEs < strsrch->pattern.PCELength - 1; nPCEs++) {
+ int64_t pce = ucol_nextProcessed(strsrch->textIter, NULL, NULL, status);
+ if (pce == UCOL_PROCESSED_NULLORDER) {
+ // at the end of the text
+ break;
+ }
+ }
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+ textOffset = ucol_getOffset(strsrch->textIter);
+ }
+ } else {
+ textOffset = ucol_getOffset(strsrch->textIter);
+ }
+
+ int32_t start = -1;
+ int32_t end = -1;
+
+ if (usearch_searchBackwards(strsrch, textOffset, &start, &end, status)) {
+ strsrch->search->matchedIndex = start;
+ strsrch->search->matchedLength = end - start;
+ return TRUE;
+ } else {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+#endif
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof.cpp
new file mode 100644
index 00000000000..58a706f0799
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof.cpp
@@ -0,0 +1,829 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+* file name: uspoof.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2008Feb13
+* created by: Andy Heninger
+*
+* Unicode Spoof Detection
+*/
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/unorm.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "uspoof_impl.h"
+#include "uassert.h"
+
+
+#if !UCONFIG_NO_NORMALIZATION
+
+U_NAMESPACE_USE
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_open(UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ SpoofImpl *si = new SpoofImpl(SpoofData::getDefault(*status), *status);
+ if (U_FAILURE(*status)) {
+ delete si;
+ si = NULL;
+ }
+ return (USpoofChecker *)si;
+}
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLength,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ SpoofData *sd = new SpoofData(data, length, *status);
+ SpoofImpl *si = new SpoofImpl(sd, *status);
+ if (U_FAILURE(*status)) {
+ delete sd;
+ delete si;
+ return NULL;
+ }
+ if (sd == NULL || si == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ delete sd;
+ delete si;
+ return NULL;
+ }
+
+ if (pActualLength != NULL) {
+ *pActualLength = sd->fRawData->fLength;
+ }
+ return reinterpret_cast<USpoofChecker *>(si);
+}
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_clone(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *src = SpoofImpl::validateThis(sc, *status);
+ if (src == NULL) {
+ return NULL;
+ }
+ SpoofImpl *result = new SpoofImpl(*src, *status); // copy constructor
+ if (U_FAILURE(*status)) {
+ delete result;
+ result = NULL;
+ }
+ return (USpoofChecker *)result;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_close(USpoofChecker *sc) {
+ UErrorCode status = U_ZERO_ERROR;
+ SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ delete This;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+
+ // Verify that the requested checks are all ones (bits) that
+ // are acceptable, known values.
+ if (checks & ~USPOOF_ALL_CHECKS) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ This->fChecks = checks;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getChecks(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return 0;
+ }
+ return This->fChecks;
+}
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+ This->setAllowedLocales(localesList, *status);
+}
+
+U_CAPI const char * U_EXPORT2
+uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return NULL;
+ }
+ return This->getAllowedLocales(*status);
+}
+
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getAllowedChars(const USpoofChecker *sc, UErrorCode *status) {
+ const UnicodeSet *result = uspoof_getAllowedUnicodeSet(sc, status);
+ return reinterpret_cast<const USet *>(result);
+}
+
+U_CAPI const UnicodeSet * U_EXPORT2
+uspoof_getAllowedUnicodeSet(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return NULL;
+ }
+ return This->fAllowedCharsSet;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status) {
+ const UnicodeSet *set = reinterpret_cast<const UnicodeSet *>(chars);
+ uspoof_setAllowedUnicodeSet(sc, set, status);
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const UnicodeSet *chars, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+ if (chars->isBogus()) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeSet *clonedSet = static_cast<UnicodeSet *>(chars->clone());
+ if (clonedSet == NULL || clonedSet->isBogus()) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ clonedSet->freeze();
+ delete This->fAllowedCharsSet;
+ This->fAllowedCharsSet = clonedSet;
+ This->fChecks |= USPOOF_CHAR_LIMIT;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check(const USpoofChecker *sc,
+ const UChar *text, int32_t length,
+ int32_t *position,
+ UErrorCode *status) {
+
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return 0;
+ }
+ if (length < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ if (length == -1) {
+ // It's not worth the bother to handle nul terminated strings everywhere.
+ // Just get the length and be done with it.
+ length = u_strlen(text);
+ }
+
+ int32_t result = 0;
+ int32_t failPos = 0x7fffffff; // TODO: do we have a #define for max int32?
+
+ // A count of the number of non-Common or inherited scripts.
+ // Needed for both the SINGLE_SCRIPT and the WHOLE/MIXED_SCIRPT_CONFUSABLE tests.
+ // Share the computation when possible. scriptCount == -1 means that we haven't
+ // done it yet.
+ int32_t scriptCount = -1;
+
+ if ((This->fChecks) & USPOOF_SINGLE_SCRIPT) {
+ scriptCount = This->scriptScan(text, length, failPos, *status);
+ // printf("scriptCount (clipped to 2) = %d\n", scriptCount);
+ if ( scriptCount >= 2) {
+ // Note: scriptCount == 2 covers all cases of the number of scripts >= 2
+ result |= USPOOF_SINGLE_SCRIPT;
+ }
+ }
+
+ if (This->fChecks & USPOOF_CHAR_LIMIT) {
+ int32_t i;
+ UChar32 c;
+ for (i=0; i<length ;) {
+ U16_NEXT(text, i, length, c);
+ if (!This->fAllowedCharsSet->contains(c)) {
+ result |= USPOOF_CHAR_LIMIT;
+ if (i < failPos) {
+ failPos = i;
+ }
+ break;
+ }
+ }
+ }
+
+ if (This->fChecks &
+ (USPOOF_WHOLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_INVISIBLE)) {
+ // These are the checks that need to be done on NFD input
+ NFDBuffer normalizedInput(text, length, *status);
+ const UChar *nfdText = normalizedInput.getBuffer();
+ int32_t nfdLength = normalizedInput.getLength();
+
+ if (This->fChecks & USPOOF_INVISIBLE) {
+
+ // scan for more than one occurence of the same non-spacing mark
+ // in a sequence of non-spacing marks.
+ int32_t i;
+ UChar32 c;
+ UChar32 firstNonspacingMark = 0;
+ UBool haveMultipleMarks = FALSE;
+ UnicodeSet marksSeenSoFar; // Set of combining marks in a single combining sequence.
+
+ for (i=0; i<nfdLength ;) {
+ U16_NEXT(nfdText, i, nfdLength, c);
+ if (u_charType(c) != U_NON_SPACING_MARK) {
+ firstNonspacingMark = 0;
+ if (haveMultipleMarks) {
+ marksSeenSoFar.clear();
+ haveMultipleMarks = FALSE;
+ }
+ continue;
+ }
+ if (firstNonspacingMark == 0) {
+ firstNonspacingMark = c;
+ continue;
+ }
+ if (!haveMultipleMarks) {
+ marksSeenSoFar.add(firstNonspacingMark);
+ haveMultipleMarks = TRUE;
+ }
+ if (marksSeenSoFar.contains(c)) {
+ // report the error, and stop scanning.
+ // No need to find more than the first failure.
+ result |= USPOOF_INVISIBLE;
+ failPos = i;
+ // TODO: Bug 8655: failPos is the position in the NFD buffer, but what we want
+ // to give back to our caller is a position in the original input string.
+ if (failPos > length) {
+ failPos = length;
+ }
+ break;
+ }
+ marksSeenSoFar.add(c);
+ }
+ }
+
+
+ if (This->fChecks & (USPOOF_WHOLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE)) {
+ // The basic test is the same for both whole and mixed script confusables.
+ // Compute the set of scripts that every input character has a confusable in.
+ // For this computation an input character is always considered to be
+ // confusable with itself in its own script.
+ // If the number of such scripts is two or more, and the input consisted of
+ // characters all from a single script, we have a whole script confusable.
+ // (The two scripts will be the original script and the one that is confusable)
+ // If the number of such scripts >= one, and the original input contained characters from
+ // more than one script, we have a mixed script confusable. (We can transform
+ // some of the characters, and end up with a visually similar string all in
+ // one script.)
+
+ if (scriptCount == -1) {
+ int32_t t;
+ scriptCount = This->scriptScan(text, length, t, *status);
+ }
+
+ ScriptSet scripts;
+ This->wholeScriptCheck(nfdText, nfdLength, &scripts, *status);
+ int32_t confusableScriptCount = scripts.countMembers();
+ //printf("confusableScriptCount = %d\n", confusableScriptCount);
+
+ if ((This->fChecks & USPOOF_WHOLE_SCRIPT_CONFUSABLE) &&
+ confusableScriptCount >= 2 &&
+ scriptCount == 1) {
+ result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+ }
+
+ if ((This->fChecks & USPOOF_MIXED_SCRIPT_CONFUSABLE) &&
+ confusableScriptCount >= 1 &&
+ scriptCount > 1) {
+ result |= USPOOF_MIXED_SCRIPT_CONFUSABLE;
+ }
+ }
+ }
+ if (position != NULL && failPos != 0x7fffffff) {
+ *position = failPos;
+ }
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+ const char *text, int32_t length,
+ int32_t *position,
+ UErrorCode *status) {
+
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ UChar stackBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar* text16 = stackBuf;
+ int32_t len16;
+
+ u_strFromUTF8(text16, USPOOF_STACK_BUFFER_SIZE, &len16, text, length, status);
+ if (U_FAILURE(*status) && *status != U_BUFFER_OVERFLOW_ERROR) {
+ return 0;
+ }
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ text16 = static_cast<UChar *>(uprv_malloc(len16 * sizeof(UChar) + 2));
+ if (text16 == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *status = U_ZERO_ERROR;
+ u_strFromUTF8(text16, len16+1, NULL, text, length, status);
+ }
+
+ int32_t position16 = -1;
+ int32_t result = uspoof_check(sc, text16, len16, &position16, status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (position16 > 0) {
+ // Translate a UTF-16 based error position back to a UTF-8 offset.
+ // u_strToUTF8() in preflight mode is an easy way to do it.
+ U_ASSERT(position16 <= len16);
+ u_strToUTF8(NULL, 0, position, text16, position16, status);
+ if (position > 0) {
+ // position is the required buffer length from u_strToUTF8, which includes
+ // space for a terminating NULL, which we don't want, hence the -1.
+ *position -= 1;
+ }
+ *status = U_ZERO_ERROR; // u_strToUTF8, above sets BUFFER_OVERFLOW_ERROR.
+ }
+
+ if (text16 != stackBuf) {
+ uprv_free(text16);
+ }
+ return result;
+
+}
+
+/* A convenience wrapper around the public uspoof_getSkeleton that handles
+ * allocating a larger buffer than provided if the original is too small.
+ */
+static UChar *getSkeleton(const USpoofChecker *sc, uint32_t type, const UChar *s, int32_t inputLength,
+ UChar *dest, int32_t destCapacity, int32_t *outputLength, UErrorCode *status) {
+ int32_t requiredCapacity = 0;
+ UChar *buf = dest;
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ requiredCapacity = uspoof_getSkeleton(sc, type, s, inputLength, dest, destCapacity, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ buf = static_cast<UChar *>(uprv_malloc(requiredCapacity * sizeof(UChar)));
+ if (buf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ *status = U_ZERO_ERROR;
+ uspoof_getSkeleton(sc, type, s, inputLength, buf, requiredCapacity, status);
+ }
+ *outputLength = requiredCapacity;
+ return buf;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+ const UChar *s1, int32_t length1,
+ const UChar *s2, int32_t length2,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ //
+ // See section 4 of UAX 39 for the algorithm for checking whether two strings are confusable,
+ // and for definitions of the types (single, whole, mixed-script) of confusables.
+
+ // We only care about a few of the check flags. Ignore the others.
+ // If no tests relavant to this function have been specified, return an error.
+ // TODO: is this really the right thing to do? It's probably an error on the caller's part,
+ // but logically we would just return 0 (no error).
+ if ((This->fChecks & (USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE |
+ USPOOF_WHOLE_SCRIPT_CONFUSABLE)) == 0) {
+ *status = U_INVALID_STATE_ERROR;
+ return 0;
+ }
+ int32_t flagsForSkeleton = This->fChecks & USPOOF_ANY_CASE;
+ UChar s1SkeletonBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *s1Skeleton;
+ int32_t s1SkeletonLength = 0;
+
+ UChar s2SkeletonBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *s2Skeleton;
+ int32_t s2SkeletonLength = 0;
+
+ int32_t result = 0;
+ int32_t t;
+ int32_t s1ScriptCount = This->scriptScan(s1, length1, t, *status);
+ int32_t s2ScriptCount = This->scriptScan(s2, length2, t, *status);
+
+ if (This->fChecks & USPOOF_SINGLE_SCRIPT_CONFUSABLE) {
+ // Do the Single Script compare.
+ if (s1ScriptCount <= 1 && s2ScriptCount <= 1) {
+ flagsForSkeleton |= USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ s1Skeleton = getSkeleton(sc, flagsForSkeleton, s1, length1, s1SkeletonBuf,
+ sizeof(s1SkeletonBuf)/sizeof(UChar), &s1SkeletonLength, status);
+ s2Skeleton = getSkeleton(sc, flagsForSkeleton, s2, length2, s2SkeletonBuf,
+ sizeof(s2SkeletonBuf)/sizeof(UChar), &s2SkeletonLength, status);
+ if (s1SkeletonLength == s2SkeletonLength && u_strncmp(s1Skeleton, s2Skeleton, s1SkeletonLength) == 0) {
+ result |= USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ }
+ if (s1Skeleton != s1SkeletonBuf) {
+ uprv_free(s1Skeleton);
+ }
+ if (s2Skeleton != s2SkeletonBuf) {
+ uprv_free(s2Skeleton);
+ }
+ }
+ }
+
+ if (result & USPOOF_SINGLE_SCRIPT_CONFUSABLE) {
+ // If the two inputs are single script confusable they cannot also be
+ // mixed or whole script confusable, according to the UAX39 definitions.
+ // So we can skip those tests.
+ return result;
+ }
+
+ // Optimization for whole script confusables test: two identifiers are whole script confusable if
+ // each is of a single script and they are mixed script confusable.
+ UBool possiblyWholeScriptConfusables =
+ s1ScriptCount <= 1 && s2ScriptCount <= 1 && (This->fChecks & USPOOF_WHOLE_SCRIPT_CONFUSABLE);
+
+ //
+ // Mixed Script Check
+ //
+ if ((This->fChecks & USPOOF_MIXED_SCRIPT_CONFUSABLE) || possiblyWholeScriptConfusables ) {
+ // For getSkeleton(), resetting the USPOOF_SINGLE_SCRIPT_CONFUSABLE flag will get us
+ // the mixed script table skeleton, which is what we want.
+ // The Any Case / Lower Case bit in the skelton flags was set at the top of the function.
+ flagsForSkeleton &= ~USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ s1Skeleton = getSkeleton(sc, flagsForSkeleton, s1, length1, s1SkeletonBuf,
+ sizeof(s1SkeletonBuf)/sizeof(UChar), &s1SkeletonLength, status);
+ s2Skeleton = getSkeleton(sc, flagsForSkeleton, s2, length2, s2SkeletonBuf,
+ sizeof(s2SkeletonBuf)/sizeof(UChar), &s2SkeletonLength, status);
+ if (s1SkeletonLength == s2SkeletonLength && u_strncmp(s1Skeleton, s2Skeleton, s1SkeletonLength) == 0) {
+ result |= USPOOF_MIXED_SCRIPT_CONFUSABLE;
+ if (possiblyWholeScriptConfusables) {
+ result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+ }
+ }
+ if (s1Skeleton != s1SkeletonBuf) {
+ uprv_free(s1Skeleton);
+ }
+ if (s2Skeleton != s2SkeletonBuf) {
+ uprv_free(s2Skeleton);
+ }
+ }
+
+ return result;
+}
+
+
+// Convenience function for converting a UTF-8 input to a UChar * string, including
+// reallocating a buffer when required. Parameters and their interpretation mostly
+// match u_strFromUTF8.
+
+static UChar * convertFromUTF8(UChar *outBuf, int32_t outBufCapacity, int32_t *outputLength,
+ const char *in, int32_t inLength, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ UChar *dest = outBuf;
+ u_strFromUTF8(dest, outBufCapacity, outputLength, in, inLength, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ dest = static_cast<UChar *>(uprv_malloc(*outputLength * sizeof(UChar)));
+ if (dest == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ *status = U_ZERO_ERROR;
+ u_strFromUTF8(dest, *outputLength, NULL, in, inLength, status);
+ }
+ return dest;
+}
+
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+ const char *s1, int32_t length1,
+ const char *s2, int32_t length2,
+ UErrorCode *status) {
+
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ UChar s1Buf[USPOOF_STACK_BUFFER_SIZE];
+ int32_t lengthS1U;
+ UChar *s1U = convertFromUTF8(s1Buf, USPOOF_STACK_BUFFER_SIZE, &lengthS1U, s1, length1, status);
+
+ UChar s2Buf[USPOOF_STACK_BUFFER_SIZE];
+ int32_t lengthS2U;
+ UChar *s2U = convertFromUTF8(s2Buf, USPOOF_STACK_BUFFER_SIZE, &lengthS2U, s2, length2, status);
+
+ int32_t results = uspoof_areConfusable(sc, s1U, lengthS1U, s2U, lengthS2U, status);
+
+ if (s1U != s1Buf) {
+ uprv_free(s1U);
+ }
+ if (s2U != s2Buf) {
+ uprv_free(s2U);
+ }
+ return results;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+ const U_NAMESPACE_QUALIFIER UnicodeString &s1,
+ const U_NAMESPACE_QUALIFIER UnicodeString &s2,
+ UErrorCode *status) {
+
+ const UChar *u1 = s1.getBuffer();
+ int32_t length1 = s1.length();
+ const UChar *u2 = s2.getBuffer();
+ int32_t length2 = s2.length();
+
+ int32_t results = uspoof_areConfusable(sc, u1, length1, u2, length2, status);
+ return results;
+}
+
+
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+ const U_NAMESPACE_QUALIFIER UnicodeString &text,
+ int32_t *position,
+ UErrorCode *status) {
+ int32_t result = uspoof_check(sc, text.getBuffer(), text.length(), position, status);
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+ uint32_t type,
+ const UChar *s, int32_t length,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *status) {
+
+ // TODO: this function could be sped up a bit
+ // Skip the input normalization when not needed, work from callers data.
+ // Put the initial skeleton straight into the caller's destination buffer.
+ // It probably won't need normalization.
+ // But these would make the structure more complicated.
+
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length<-1 || destCapacity<0 || (destCapacity==0 && dest!=NULL) ||
+ (type & ~(USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_ANY_CASE)) != 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ int32_t tableMask = 0;
+ switch (type) {
+ case 0:
+ tableMask = USPOOF_ML_TABLE_FLAG;
+ break;
+ case USPOOF_SINGLE_SCRIPT_CONFUSABLE:
+ tableMask = USPOOF_SL_TABLE_FLAG;
+ break;
+ case USPOOF_ANY_CASE:
+ tableMask = USPOOF_MA_TABLE_FLAG;
+ break;
+ case USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_ANY_CASE:
+ tableMask = USPOOF_SA_TABLE_FLAG;
+ break;
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ // NFD transform of the user supplied input
+
+ UChar nfdStackBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *nfdInput = nfdStackBuf;
+ int32_t normalizedLen = unorm_normalize(
+ s, length, UNORM_NFD, 0, nfdInput, USPOOF_STACK_BUFFER_SIZE, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ nfdInput = (UChar *)uprv_malloc((normalizedLen+1)*sizeof(UChar));
+ if (nfdInput == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *status = U_ZERO_ERROR;
+ normalizedLen = unorm_normalize(s, length, UNORM_NFD, 0,
+ nfdInput, normalizedLen+1, status);
+ }
+ if (U_FAILURE(*status)) {
+ if (nfdInput != nfdStackBuf) {
+ uprv_free(nfdInput);
+ }
+ return 0;
+ }
+
+ // buffer to hold the Unicode defined skeleton mappings for a single code point
+ UChar buf[USPOOF_MAX_SKELETON_EXPANSION];
+
+ // Apply the skeleton mapping to the NFD normalized input string
+ // Accumulate the skeleton, possibly unnormalized, in a UnicodeString.
+ int32_t inputIndex = 0;
+ UnicodeString skelStr;
+ while (inputIndex < normalizedLen) {
+ UChar32 c;
+ U16_NEXT(nfdInput, inputIndex, normalizedLen, c);
+ int32_t replaceLen = This->confusableLookup(c, tableMask, buf);
+ skelStr.append(buf, replaceLen);
+ }
+
+ if (nfdInput != nfdStackBuf) {
+ uprv_free(nfdInput);
+ }
+
+ const UChar *result = skelStr.getBuffer();
+ int32_t resultLen = skelStr.length();
+ UChar *normedResult = NULL;
+
+ // Check the skeleton for NFD, normalize it if needed.
+ // Unnormalized results should be very rare.
+ if (!unorm_isNormalized(result, resultLen, UNORM_NFD, status)) {
+ normalizedLen = unorm_normalize(result, resultLen, UNORM_NFD, 0, NULL, 0, status);
+ normedResult = static_cast<UChar *>(uprv_malloc((normalizedLen+1)*sizeof(UChar)));
+ if (normedResult == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *status = U_ZERO_ERROR;
+ unorm_normalize(result, resultLen, UNORM_NFD, 0, normedResult, normalizedLen+1, status);
+ result = normedResult;
+ resultLen = normalizedLen;
+ }
+
+ // Copy the skeleton to the caller's buffer
+ if (U_SUCCESS(*status)) {
+ if (destCapacity == 0 || resultLen > destCapacity) {
+ *status = resultLen>destCapacity ? U_BUFFER_OVERFLOW_ERROR : U_STRING_NOT_TERMINATED_WARNING;
+ } else {
+ u_memcpy(dest, result, resultLen);
+ if (destCapacity > resultLen) {
+ dest[resultLen] = 0;
+ } else {
+ *status = U_STRING_NOT_TERMINATED_WARNING;
+ }
+ }
+ }
+ uprv_free(normedResult);
+ return resultLen;
+}
+
+
+
+U_CAPI UnicodeString & U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+ uint32_t type,
+ const UnicodeString &s,
+ UnicodeString &dest,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return dest;
+ }
+ dest.remove();
+
+ const UChar *str = s.getBuffer();
+ int32_t strLen = s.length();
+ UChar smallBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *buf = smallBuf;
+ int32_t outputSize = uspoof_getSkeleton(sc, type, str, strLen, smallBuf, USPOOF_STACK_BUFFER_SIZE, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ buf = static_cast<UChar *>(uprv_malloc((outputSize+1)*sizeof(UChar)));
+ if (buf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return dest;
+ }
+ *status = U_ZERO_ERROR;
+ uspoof_getSkeleton(sc, type, str, strLen, buf, outputSize+1, status);
+ }
+ if (U_SUCCESS(*status)) {
+ dest.setTo(buf, outputSize);
+ }
+
+ if (buf != smallBuf) {
+ uprv_free(buf);
+ }
+ return dest;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+ uint32_t type,
+ const char *s, int32_t length,
+ char *dest, int32_t destCapacity,
+ UErrorCode *status) {
+ // Lacking a UTF-8 normalization API, just converting the input to
+ // UTF-16 seems as good an approach as any. In typical use, input will
+ // be an identifier, which is to say not too long for stack buffers.
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ // Buffers for the UChar form of the input and skeleton strings.
+ UChar smallInBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *inBuf = smallInBuf;
+ UChar smallOutBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *outBuf = smallOutBuf;
+
+ int32_t lengthInUChars = 0;
+ int32_t skelLengthInUChars = 0;
+ int32_t skelLengthInUTF8 = 0;
+
+ u_strFromUTF8(inBuf, USPOOF_STACK_BUFFER_SIZE, &lengthInUChars,
+ s, length, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ inBuf = static_cast<UChar *>(uprv_malloc((lengthInUChars+1)*sizeof(UChar)));
+ if (inBuf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ *status = U_ZERO_ERROR;
+ u_strFromUTF8(inBuf, lengthInUChars+1, &lengthInUChars,
+ s, length, status);
+ }
+
+ skelLengthInUChars = uspoof_getSkeleton(sc, type, inBuf, lengthInUChars,
+ outBuf, USPOOF_STACK_BUFFER_SIZE, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ outBuf = static_cast<UChar *>(uprv_malloc((skelLengthInUChars+1)*sizeof(UChar)));
+ if (outBuf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ *status = U_ZERO_ERROR;
+ skelLengthInUChars = uspoof_getSkeleton(sc, type, inBuf, lengthInUChars,
+ outBuf, skelLengthInUChars+1, status);
+ }
+
+ u_strToUTF8(dest, destCapacity, &skelLengthInUTF8,
+ outBuf, skelLengthInUChars, status);
+
+ cleanup:
+ if (inBuf != smallInBuf) {
+ uprv_free(inBuf);
+ }
+ if (outBuf != smallOutBuf) {
+ uprv_free(outBuf);
+ }
+ return skelLengthInUTF8;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,void *buf, int32_t capacity, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ U_ASSERT(U_FAILURE(*status));
+ return 0;
+ }
+ int32_t dataSize = This->fSpoofData->fRawData->fLength;
+ if (capacity < dataSize) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ return dataSize;
+ }
+ uprv_memcpy(buf, This->fSpoofData->fRawData, dataSize);
+ return dataSize;
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_build.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_build.cpp
new file mode 100644
index 00000000000..681282e0a89
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_build.cpp
@@ -0,0 +1,85 @@
+/*
+ ***************************************************************************
+ * Copyright (C) 2008-2009, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***************************************************************************
+ * file name: uspoof_build.cpp
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2008 Dec 8
+ * created by: Andy Heninger
+ *
+ * Unicode Spoof Detection Data Builder
+ * Builder-related functions are kept in separate files so that applications not needing
+ * the builder can more easily exclude them, typically by means of static linking.
+ *
+ * There are three relatively independent sets of Spoof data,
+ * Confusables,
+ * Whole Script Confusables
+ * ID character extensions.
+ *
+ * The data tables for each are built separately, each from its own definitions
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/unorm.h"
+#include "unicode/uregex.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "uspoof_impl.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "uassert.h"
+#include "uarrsort.h"
+#include "uspoof_conf.h"
+#include "uspoof_wsconf.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+U_NAMESPACE_USE
+
+
+// The main data building function
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSource(const char *confusables, int32_t confusablesLen,
+ const char *confusablesWholeScript, int32_t confusablesWholeScriptLen,
+ int32_t *errorType, UParseError *pe, UErrorCode *status) {
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+#if UCONFIG_NO_REGULAR_EXPRESSIONS
+ *status = U_UNSUPPORTED_ERROR;
+ return NULL;
+#else
+ if (errorType!=NULL) {
+ *errorType = 0;
+ }
+ if (pe != NULL) {
+ pe->line = 0;
+ pe->offset = 0;
+ pe->preContext[0] = 0;
+ pe->postContext[0] = 0;
+ }
+
+ // Set up a shell of a spoof detector, with empty data.
+ SpoofData *newSpoofData = new SpoofData(*status);
+ SpoofImpl *This = new SpoofImpl(newSpoofData, *status);
+
+ // Compile the binary data from the source (text) format.
+ ConfusabledataBuilder::buildConfusableData(This, confusables, confusablesLen, errorType, pe, *status);
+ buildWSConfusableData(This, confusablesWholeScript, confusablesWholeScriptLen, pe, *status);
+
+ if (U_FAILURE(*status)) {
+ delete This;
+ This = NULL;
+ }
+ return (USpoofChecker *)This;
+#endif // UCONFIG_NO_REGULAR_EXPRESSIONS
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.cpp
new file mode 100644
index 00000000000..c7a8c62ae50
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.cpp
@@ -0,0 +1,603 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+* file name: uspoof_conf.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2009Jan05 (refactoring earlier files)
+* created by: Andy Heninger
+*
+* Internal classes for compililing confusable data into its binary (runtime) form.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/unorm.h"
+#include "unicode/uregex.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "uspoof_impl.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "uassert.h"
+#include "uarrsort.h"
+#include "uspoof_conf.h"
+
+U_NAMESPACE_USE
+
+
+//---------------------------------------------------------------------
+//
+// buildConfusableData Compile the source confusable data, as defined by
+// the Unicode data file confusables.txt, into the binary
+// structures used by the confusable detector.
+//
+// The binary structures are described in uspoof_impl.h
+//
+// 1. parse the data, building 4 hash tables, one each for the SL, SA, ML and MA
+// tables. Each maps from a UChar32 to a String.
+//
+// 2. Sort all of the strings encountered by length, since they will need to
+// be stored in that order in the final string table.
+//
+// 3. Build a list of keys (UChar32s) from the four mapping tables. Sort the
+// list because that will be the ordering of our runtime table.
+//
+// 4. Generate the run time string table. This is generated before the key & value
+// tables because we need the string indexes when building those tables.
+//
+// 5. Build the run-time key and value tables. These are parallel tables, and are built
+// at the same time
+//
+
+SPUString::SPUString(UnicodeString *s) {
+ fStr = s;
+ fStrTableIndex = 0;
+}
+
+
+SPUString::~SPUString() {
+ delete fStr;
+}
+
+
+SPUStringPool::SPUStringPool(UErrorCode &status) : fVec(NULL), fHash(NULL) {
+ fVec = new UVector(status);
+ fHash = uhash_open(uhash_hashUnicodeString, // key hash function
+ uhash_compareUnicodeString, // Key Comparator
+ NULL, // Value Comparator
+ &status);
+}
+
+
+SPUStringPool::~SPUStringPool() {
+ int i;
+ for (i=fVec->size()-1; i>=0; i--) {
+ SPUString *s = static_cast<SPUString *>(fVec->elementAt(i));
+ delete s;
+ }
+ delete fVec;
+ uhash_close(fHash);
+}
+
+
+int32_t SPUStringPool::size() {
+ return fVec->size();
+}
+
+SPUString *SPUStringPool::getByIndex(int32_t index) {
+ SPUString *retString = (SPUString *)fVec->elementAt(index);
+ return retString;
+}
+
+
+// Comparison function for ordering strings in the string pool.
+// Compare by length first, then, within a group of the same length,
+// by code point order.
+// Conforms to the type signature for a USortComparator in uvector.h
+
+static int8_t U_CALLCONV SPUStringCompare(UHashTok left, UHashTok right) {
+ const SPUString *sL = const_cast<const SPUString *>(
+ static_cast<SPUString *>(left.pointer));
+ const SPUString *sR = const_cast<const SPUString *>(
+ static_cast<SPUString *>(right.pointer));
+ int32_t lenL = sL->fStr->length();
+ int32_t lenR = sR->fStr->length();
+ if (lenL < lenR) {
+ return -1;
+ } else if (lenL > lenR) {
+ return 1;
+ } else {
+ return sL->fStr->compare(*(sR->fStr));
+ }
+}
+
+void SPUStringPool::sort(UErrorCode &status) {
+ fVec->sort(SPUStringCompare, status);
+}
+
+
+SPUString *SPUStringPool::addString(UnicodeString *src, UErrorCode &status) {
+ SPUString *hashedString = static_cast<SPUString *>(uhash_get(fHash, src));
+ if (hashedString != NULL) {
+ delete src;
+ } else {
+ hashedString = new SPUString(src);
+ uhash_put(fHash, src, hashedString, &status);
+ fVec->addElement(hashedString, status);
+ }
+ return hashedString;
+}
+
+
+
+ConfusabledataBuilder::ConfusabledataBuilder(SpoofImpl *spImpl, UErrorCode &status) :
+ fSpoofImpl(spImpl),
+ fInput(NULL),
+ fSLTable(NULL),
+ fSATable(NULL),
+ fMLTable(NULL),
+ fMATable(NULL),
+ fKeySet(NULL),
+ fKeyVec(NULL),
+ fValueVec(NULL),
+ fStringTable(NULL),
+ fStringLengthsTable(NULL),
+ stringPool(NULL),
+ fParseLine(NULL),
+ fParseHexNum(NULL),
+ fLineNum(0)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fSLTable = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status);
+ fSATable = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status);
+ fMLTable = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status);
+ fMATable = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status);
+ fKeySet = new UnicodeSet();
+ fKeyVec = new UVector(status);
+ fValueVec = new UVector(status);
+ stringPool = new SPUStringPool(status);
+}
+
+
+ConfusabledataBuilder::~ConfusabledataBuilder() {
+ uprv_free(fInput);
+ uregex_close(fParseLine);
+ uregex_close(fParseHexNum);
+ uhash_close(fSLTable);
+ uhash_close(fSATable);
+ uhash_close(fMLTable);
+ uhash_close(fMATable);
+ delete fKeySet;
+ delete fKeyVec;
+ delete fStringTable;
+ delete fStringLengthsTable;
+ delete fValueVec;
+ delete stringPool;
+}
+
+
+void ConfusabledataBuilder::buildConfusableData(SpoofImpl * spImpl, const char * confusables,
+ int32_t confusablesLen, int32_t *errorType, UParseError *pe, UErrorCode &status) {
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ ConfusabledataBuilder builder(spImpl, status);
+ builder.build(confusables, confusablesLen, status);
+ if (U_FAILURE(status) && errorType != NULL) {
+ *errorType = USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ pe->line = builder.fLineNum;
+ }
+}
+
+
+void ConfusabledataBuilder::build(const char * confusables, int32_t confusablesLen,
+ UErrorCode &status) {
+
+ // Convert the user input data from UTF-8 to UChar (UTF-16)
+ int32_t inputLen = 0;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ u_strFromUTF8(NULL, 0, &inputLen, confusables, confusablesLen, &status);
+ if (status != U_BUFFER_OVERFLOW_ERROR) {
+ return;
+ }
+ status = U_ZERO_ERROR;
+ fInput = static_cast<UChar *>(uprv_malloc((inputLen+1) * sizeof(UChar)));
+ if (fInput == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ u_strFromUTF8(fInput, inputLen+1, NULL, confusables, confusablesLen, &status);
+
+
+ // Regular Expression to parse a line from Confusables.txt. The expression will match
+ // any line. What was matched is determined by examining which capture groups have a match.
+ // Capture Group 1: the source char
+ // Capture Group 2: the replacement chars
+ // Capture Group 3-6 the table type, SL, SA, ML, or MA
+ // Capture Group 7: A blank or comment only line.
+ // Capture Group 8: A syntactically invalid line. Anything that didn't match before.
+ // Example Line from the confusables.txt source file:
+ // "1D702 ; 006E 0329 ; SL # MATHEMATICAL ITALIC SMALL ETA ... "
+ UnicodeString pattern(
+ "(?m)^[ \\t]*([0-9A-Fa-f]+)[ \\t]+;" // Match the source char
+ "[ \\t]*([0-9A-Fa-f]+" // Match the replacement char(s)
+ "(?:[ \\t]+[0-9A-Fa-f]+)*)[ \\t]*;" // (continued)
+ "\\s*(?:(SL)|(SA)|(ML)|(MA))" // Match the table type
+ "[ \\t]*(?:#.*?)?$" // Match any trailing #comment
+ "|^([ \\t]*(?:#.*?)?)$" // OR match empty lines or lines with only a #comment
+ "|^(.*?)$", -1, US_INV); // OR match any line, which catches illegal lines.
+ // TODO: Why are we using the regex C API here? C++ would just take UnicodeString...
+ fParseLine = uregex_open(pattern.getBuffer(), pattern.length(), 0, NULL, &status);
+
+ // Regular expression for parsing a hex number out of a space-separated list of them.
+ // Capture group 1 gets the number, with spaces removed.
+ pattern = UNICODE_STRING_SIMPLE("\\s*([0-9A-F]+)");
+ fParseHexNum = uregex_open(pattern.getBuffer(), pattern.length(), 0, NULL, &status);
+
+ // Zap any Byte Order Mark at the start of input. Changing it to a space is benign
+ // given the syntax of the input.
+ if (*fInput == 0xfeff) {
+ *fInput = 0x20;
+ }
+
+ // Parse the input, one line per iteration of this loop.
+ uregex_setText(fParseLine, fInput, inputLen, &status);
+ while (uregex_findNext(fParseLine, &status)) {
+ fLineNum++;
+ if (uregex_start(fParseLine, 7, &status) >= 0) {
+ // this was a blank or comment line.
+ continue;
+ }
+ if (uregex_start(fParseLine, 8, &status) >= 0) {
+ // input file syntax error.
+ status = U_PARSE_ERROR;
+ return;
+ }
+
+ // We have a good input line. Extract the key character and mapping string, and
+ // put them into the appropriate mapping table.
+ UChar32 keyChar = SpoofImpl::ScanHex(fInput, uregex_start(fParseLine, 1, &status),
+ uregex_end(fParseLine, 1, &status), status);
+
+ int32_t mapStringStart = uregex_start(fParseLine, 2, &status);
+ int32_t mapStringLength = uregex_end(fParseLine, 2, &status) - mapStringStart;
+ uregex_setText(fParseHexNum, &fInput[mapStringStart], mapStringLength, &status);
+
+ UnicodeString *mapString = new UnicodeString();
+ if (mapString == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ while (uregex_findNext(fParseHexNum, &status)) {
+ UChar32 c = SpoofImpl::ScanHex(&fInput[mapStringStart], uregex_start(fParseHexNum, 1, &status),
+ uregex_end(fParseHexNum, 1, &status), status);
+ mapString->append(c);
+ }
+ U_ASSERT(mapString->length() >= 1);
+
+ // Put the map (value) string into the string pool
+ // This a little like a Java intern() - any duplicates will be eliminated.
+ SPUString *smapString = stringPool->addString(mapString, status);
+
+ // Add the UChar32 -> string mapping to the appropriate table.
+ UHashtable *table = uregex_start(fParseLine, 3, &status) >= 0 ? fSLTable :
+ uregex_start(fParseLine, 4, &status) >= 0 ? fSATable :
+ uregex_start(fParseLine, 5, &status) >= 0 ? fMLTable :
+ uregex_start(fParseLine, 6, &status) >= 0 ? fMATable :
+ NULL;
+ U_ASSERT(table != NULL);
+ uhash_iput(table, keyChar, smapString, &status);
+ fKeySet->add(keyChar);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ // Input data is now all parsed and collected.
+ // Now create the run-time binary form of the data.
+ //
+ // This is done in two steps. First the data is assembled into vectors and strings,
+ // for ease of construction, then the contents of these collections are dumped
+ // into the actual raw-bytes data storage.
+
+ // Build up the string array, and record the index of each string therein
+ // in the (build time only) string pool.
+ // Strings of length one are not entered into the strings array.
+ // At the same time, build up the string lengths table, which records the
+ // position in the string table of the first string of each length >= 4.
+ // (Strings in the table are sorted by length)
+ stringPool->sort(status);
+ fStringTable = new UnicodeString();
+ fStringLengthsTable = new UVector(status);
+ int32_t previousStringLength = 0;
+ int32_t previousStringIndex = 0;
+ int32_t poolSize = stringPool->size();
+ int32_t i;
+ for (i=0; i<poolSize; i++) {
+ SPUString *s = stringPool->getByIndex(i);
+ int32_t strLen = s->fStr->length();
+ int32_t strIndex = fStringTable->length();
+ U_ASSERT(strLen >= previousStringLength);
+ if (strLen == 1) {
+ // strings of length one do not get an entry in the string table.
+ // Keep the single string character itself here, which is the same
+ // convention that is used in the final run-time string table index.
+ s->fStrTableIndex = s->fStr->charAt(0);
+ } else {
+ if ((strLen > previousStringLength) && (previousStringLength >= 4)) {
+ fStringLengthsTable->addElement(previousStringIndex, status);
+ fStringLengthsTable->addElement(previousStringLength, status);
+ }
+ s->fStrTableIndex = strIndex;
+ fStringTable->append(*(s->fStr));
+ }
+ previousStringLength = strLen;
+ previousStringIndex = strIndex;
+ }
+ // Make the final entry to the string lengths table.
+ // (it holds an entry for the _last_ string of each length, so adding the
+ // final one doesn't happen in the main loop because no longer string was encountered.)
+ if (previousStringLength >= 4) {
+ fStringLengthsTable->addElement(previousStringIndex, status);
+ fStringLengthsTable->addElement(previousStringLength, status);
+ }
+
+ // Construct the compile-time Key and Value tables
+ //
+ // For each key code point, check which mapping tables it applies to,
+ // and create the final data for the key & value structures.
+ //
+ // The four logical mapping tables are conflated into one combined table.
+ // If multiple logical tables have the same mapping for some key, they
+ // share a single entry in the combined table.
+ // If more than one mapping exists for the same key code point, multiple
+ // entries will be created in the table
+
+ for (int32_t range=0; range<fKeySet->getRangeCount(); range++) {
+ // It is an oddity of the UnicodeSet API that simply enumerating the contained
+ // code points requires a nested loop.
+ for (UChar32 keyChar=fKeySet->getRangeStart(range);
+ keyChar <= fKeySet->getRangeEnd(range); keyChar++) {
+ addKeyEntry(keyChar, fSLTable, USPOOF_SL_TABLE_FLAG, status);
+ addKeyEntry(keyChar, fSATable, USPOOF_SA_TABLE_FLAG, status);
+ addKeyEntry(keyChar, fMLTable, USPOOF_ML_TABLE_FLAG, status);
+ addKeyEntry(keyChar, fMATable, USPOOF_MA_TABLE_FLAG, status);
+ }
+ }
+
+ // Put the assembled data into the flat runtime array
+ outputData(status);
+
+ // All of the intermediate allocated data belongs to the ConfusabledataBuilder
+ // object (this), and is deleted in the destructor.
+ return;
+}
+
+//
+// outputData The confusable data has been compiled and stored in intermediate
+// collections and strings. Copy it from there to the final flat
+// binary array.
+//
+// Note that as each section is added to the output data, the
+// expand (reserveSpace() function will likely relocate it in memory.
+// Be careful with pointers.
+//
+void ConfusabledataBuilder::outputData(UErrorCode &status) {
+
+ U_ASSERT(fSpoofImpl->fSpoofData->fDataOwned == TRUE);
+
+ // The Key Table
+ // While copying the keys to the runtime array,
+ // also sanity check that they are sorted.
+
+ int32_t numKeys = fKeyVec->size();
+ int32_t *keys =
+ static_cast<int32_t *>(fSpoofImpl->fSpoofData->reserveSpace(numKeys*sizeof(int32_t), status));
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int i;
+ int32_t previousKey = 0;
+ for (i=0; i<numKeys; i++) {
+ int32_t key = fKeyVec->elementAti(i);
+ U_ASSERT((key & 0x00ffffff) >= (previousKey & 0x00ffffff));
+ U_ASSERT((key & 0xff000000) != 0);
+ keys[i] = key;
+ previousKey = key;
+ }
+ SpoofDataHeader *rawData = fSpoofImpl->fSpoofData->fRawData;
+ rawData->fCFUKeys = (int32_t)((char *)keys - (char *)rawData);
+ rawData->fCFUKeysSize = numKeys;
+ fSpoofImpl->fSpoofData->fCFUKeys = keys;
+
+
+ // The Value Table, parallels the key table
+ int32_t numValues = fValueVec->size();
+ U_ASSERT(numKeys == numValues);
+ uint16_t *values =
+ static_cast<uint16_t *>(fSpoofImpl->fSpoofData->reserveSpace(numKeys*sizeof(uint16_t), status));
+ if (U_FAILURE(status)) {
+ return;
+ }
+ for (i=0; i<numValues; i++) {
+ uint32_t value = static_cast<uint32_t>(fValueVec->elementAti(i));
+ U_ASSERT(value < 0xffff);
+ values[i] = static_cast<uint16_t>(value);
+ }
+ rawData = fSpoofImpl->fSpoofData->fRawData;
+ rawData->fCFUStringIndex = (int32_t)((char *)values - (char *)rawData);
+ rawData->fCFUStringIndexSize = numValues;
+ fSpoofImpl->fSpoofData->fCFUValues = values;
+
+ // The Strings Table.
+
+ uint32_t stringsLength = fStringTable->length();
+ // Reserve an extra space so the string will be nul-terminated. This is
+ // only a convenience, for when debugging; it is not needed otherwise.
+ UChar *strings =
+ static_cast<UChar *>(fSpoofImpl->fSpoofData->reserveSpace(stringsLength*sizeof(UChar)+2, status));
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fStringTable->extract(strings, stringsLength+1, status);
+ rawData = fSpoofImpl->fSpoofData->fRawData;
+ U_ASSERT(rawData->fCFUStringTable == 0);
+ rawData->fCFUStringTable = (int32_t)((char *)strings - (char *)rawData);
+ rawData->fCFUStringTableLen = stringsLength;
+ fSpoofImpl->fSpoofData->fCFUStrings = strings;
+
+ // The String Lengths Table
+ // While copying into the runtime array do some sanity checks on the values
+ // Each complete entry contains two fields, an index and an offset.
+ // Lengths should increase with each entry.
+ // Offsets should be less than the size of the string table.
+ int32_t lengthTableLength = fStringLengthsTable->size();
+ uint16_t *stringLengths =
+ static_cast<uint16_t *>(fSpoofImpl->fSpoofData->reserveSpace(lengthTableLength*sizeof(uint16_t), status));
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int32_t destIndex = 0;
+ uint32_t previousLength = 0;
+ for (i=0; i<lengthTableLength; i+=2) {
+ uint32_t offset = static_cast<uint32_t>(fStringLengthsTable->elementAti(i));
+ uint32_t length = static_cast<uint32_t>(fStringLengthsTable->elementAti(i+1));
+ U_ASSERT(offset < stringsLength);
+ U_ASSERT(length < 40);
+ U_ASSERT(length > previousLength);
+ stringLengths[destIndex++] = static_cast<uint16_t>(offset);
+ stringLengths[destIndex++] = static_cast<uint16_t>(length);
+ previousLength = length;
+ }
+ rawData = fSpoofImpl->fSpoofData->fRawData;
+ rawData->fCFUStringLengths = (int32_t)((char *)stringLengths - (char *)rawData);
+ // Note: StringLengthsSize in the raw data is the number of complete entries,
+ // each consisting of a pair of 16 bit values, hence the divide by 2.
+ rawData->fCFUStringLengthsSize = lengthTableLength / 2;
+ fSpoofImpl->fSpoofData->fCFUStringLengths =
+ reinterpret_cast<SpoofStringLengthsElement *>(stringLengths);
+}
+
+
+
+// addKeyEntry Construction of the confusable Key and Mapping Values tables.
+// This is an intermediate point in the building process.
+// We already have the mappings in the hash tables fSLTable, etc.
+// This function builds corresponding run-time style table entries into
+// fKeyVec and fValueVec
+
+void ConfusabledataBuilder::addKeyEntry(
+ UChar32 keyChar, // The key character
+ UHashtable *table, // The table, one of SATable, MATable, etc.
+ int32_t tableFlag, // One of USPOOF_SA_TABLE_FLAG, etc.
+ UErrorCode &status) {
+
+ SPUString *targetMapping = static_cast<SPUString *>(uhash_iget(table, keyChar));
+ if (targetMapping == NULL) {
+ // No mapping for this key character.
+ // (This function is called for all four tables for each key char that
+ // is seen anywhere, so this no entry cases are very much expected.)
+ return;
+ }
+
+ // Check whether there is already an entry with the correct mapping.
+ // If so, simply set the flag in the keyTable saying that the existing entry
+ // applies to the table that we're doing now.
+
+ UBool keyHasMultipleValues = FALSE;
+ int32_t i;
+ for (i=fKeyVec->size()-1; i>=0 ; i--) {
+ int32_t key = fKeyVec->elementAti(i);
+ if ((key & 0x0ffffff) != keyChar) {
+ // We have now checked all existing key entries for this key char (if any)
+ // without finding one with the same mapping.
+ break;
+ }
+ UnicodeString mapping = getMapping(i);
+ if (mapping == *(targetMapping->fStr)) {
+ // The run time entry we are currently testing has the correct mapping.
+ // Set the flag in it indicating that it applies to the new table also.
+ key |= tableFlag;
+ fKeyVec->setElementAt(key, i);
+ return;
+ }
+ keyHasMultipleValues = TRUE;
+ }
+
+ // Need to add a new entry to the binary data being built for this mapping.
+ // Includes adding entries to both the key table and the parallel values table.
+
+ int32_t newKey = keyChar | tableFlag;
+ if (keyHasMultipleValues) {
+ newKey |= USPOOF_KEY_MULTIPLE_VALUES;
+ }
+ int32_t adjustedMappingLength = targetMapping->fStr->length() - 1;
+ if (adjustedMappingLength>3) {
+ adjustedMappingLength = 3;
+ }
+ newKey |= adjustedMappingLength << USPOOF_KEY_LENGTH_SHIFT;
+
+ int32_t newData = targetMapping->fStrTableIndex;
+
+ fKeyVec->addElement(newKey, status);
+ fValueVec->addElement(newData, status);
+
+ // If the preceding key entry is for the same key character (but with a different mapping)
+ // set the multiple-values flag on it.
+ if (keyHasMultipleValues) {
+ int32_t previousKeyIndex = fKeyVec->size() - 2;
+ int32_t previousKey = fKeyVec->elementAti(previousKeyIndex);
+ previousKey |= USPOOF_KEY_MULTIPLE_VALUES;
+ fKeyVec->setElementAt(previousKey, previousKeyIndex);
+ }
+}
+
+
+
+UnicodeString ConfusabledataBuilder::getMapping(int32_t index) {
+ int32_t key = fKeyVec->elementAti(index);
+ int32_t value = fValueVec->elementAti(index);
+ int32_t length = USPOOF_KEY_LENGTH_FIELD(key);
+ int32_t lastIndexWithLen;
+ switch (length) {
+ case 0:
+ return UnicodeString(static_cast<UChar>(value));
+ case 1:
+ case 2:
+ return UnicodeString(*fStringTable, value, length+1);
+ case 3:
+ length = 0;
+ int32_t i;
+ for (i=0; i<fStringLengthsTable->size(); i+=2) {
+ lastIndexWithLen = fStringLengthsTable->elementAti(i);
+ if (value <= lastIndexWithLen) {
+ length = fStringLengthsTable->elementAti(i+1);
+ break;
+ }
+ }
+ U_ASSERT(length>=3);
+ return UnicodeString(*fStringTable, value, length);
+ default:
+ U_ASSERT(FALSE);
+ }
+ return UnicodeString();
+}
+
+#endif
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.h b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.h
new file mode 100644
index 00000000000..b2be5d0388e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_conf.h
@@ -0,0 +1,132 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+* file name: uspoof_conf.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2009Jan05
+* created by: Andy Heninger
+*
+* Internal classes for compiling confusable data into its binary (runtime) form.
+*/
+
+#ifndef __USPOOF_BUILDCONF_H__
+#define __USPOOF_BUILDCONF_H__
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "uspoof_impl.h"
+
+U_NAMESPACE_BEGIN
+
+// SPUString
+// Holds a string that is the result of one of the mappings defined
+// by the confusable mapping data (confusables.txt from Unicode.org)
+// Instances of SPUString exist during the compilation process only.
+
+struct SPUString : public UMemory {
+ UnicodeString *fStr; // The actual string.
+ int32_t fStrTableIndex; // Index into the final runtime data for this string.
+ // (or, for length 1, the single string char itself,
+ // there being no string table entry for it.)
+ SPUString(UnicodeString *s);
+ ~SPUString();
+};
+
+
+// String Pool A utility class for holding the strings that are the result of
+// the spoof mappings. These strings will utimately end up in the
+// run-time String Table.
+// This is sort of like a sorted set of strings, except that ICU's anemic
+// built-in collections don't support those, so it is implemented with a
+// combination of a uhash and a UVector.
+
+
+class SPUStringPool : public UMemory {
+ public:
+ SPUStringPool(UErrorCode &status);
+ ~SPUStringPool();
+
+ // Add a string. Return the string from the table.
+ // If the input parameter string is already in the table, delete the
+ // input parameter and return the existing string.
+ SPUString *addString(UnicodeString *src, UErrorCode &status);
+
+
+ // Get the n-th string in the collection.
+ SPUString *getByIndex(int32_t i);
+
+ // Sort the contents; affects the ordering of getByIndex().
+ void sort(UErrorCode &status);
+
+ int32_t size();
+
+ private:
+ UVector *fVec; // Elements are SPUString *
+ UHashtable *fHash; // Key: UnicodeString Value: SPUString
+};
+
+
+// class ConfusabledataBuilder
+// An instance of this class exists while the confusable data is being built from source.
+// It encapsulates the intermediate data structures that are used for building.
+// It exports one static function, to do a confusable data build.
+
+class ConfusabledataBuilder : public UMemory {
+ private:
+ SpoofImpl *fSpoofImpl;
+ UChar *fInput;
+ UHashtable *fSLTable;
+ UHashtable *fSATable;
+ UHashtable *fMLTable;
+ UHashtable *fMATable;
+ UnicodeSet *fKeySet; // A set of all keys (UChar32s) that go into the four mapping tables.
+
+ // The binary data is first assembled into the following four collections, then
+ // copied to its final raw-memory destination.
+ UVector *fKeyVec;
+ UVector *fValueVec;
+ UnicodeString *fStringTable;
+ UVector *fStringLengthsTable;
+
+ SPUStringPool *stringPool;
+ URegularExpression *fParseLine;
+ URegularExpression *fParseHexNum;
+ int32_t fLineNum;
+
+ ConfusabledataBuilder(SpoofImpl *spImpl, UErrorCode &status);
+ ~ConfusabledataBuilder();
+ void build(const char * confusables, int32_t confusablesLen, UErrorCode &status);
+
+ // Add an entry to the key and value tables being built
+ // input: data from SLTable, MATable, etc.
+ // outut: entry added to fKeyVec and fValueVec
+ void addKeyEntry(UChar32 keyChar, // The key character
+ UHashtable *table, // The table, one of SATable, MATable, etc.
+ int32_t tableFlag, // One of USPOOF_SA_TABLE_FLAG, etc.
+ UErrorCode &status);
+
+ // From an index into fKeyVec & fValueVec
+ // get a UnicodeString with the corresponding mapping.
+ UnicodeString getMapping(int32_t index);
+
+ // Populate the final binary output data array with the compiled data.
+ void outputData(UErrorCode &status);
+
+ public:
+ static void buildConfusableData(SpoofImpl *spImpl, const char * confusables,
+ int32_t confusablesLen, int32_t *errorType, UParseError *pe, UErrorCode &status);
+};
+U_NAMESPACE_END
+
+#endif
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif // __USPOOF_BUILDCONF_H__
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.cpp
new file mode 100644
index 00000000000..e43072273d5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.cpp
@@ -0,0 +1,976 @@
+/*
+**********************************************************************
+* Copyright (C) 2008-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/unorm.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "utrie2.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "udatamem.h"
+#include "umutex.h"
+#include "udataswp.h"
+#include "uassert.h"
+#include "uspoof_impl.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
+
+SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode &status) :
+ fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) , fAllowedLocales(uprv_strdup("")) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fMagic = USPOOF_MAGIC;
+ fSpoofData = data;
+ fChecks = USPOOF_ALL_CHECKS;
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
+ if (allowedCharsSet == NULL || fAllowedLocales == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ allowedCharsSet->freeze();
+ fAllowedCharsSet = allowedCharsSet;
+}
+
+
+SpoofImpl::SpoofImpl() {
+ fMagic = USPOOF_MAGIC;
+ fSpoofData = NULL;
+ fChecks = USPOOF_ALL_CHECKS;
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
+ allowedCharsSet->freeze();
+ fAllowedCharsSet = allowedCharsSet;
+ fAllowedLocales = uprv_strdup("");
+}
+
+
+// Copy Constructor, used by the user level clone() function.
+SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) :
+ fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fMagic = src.fMagic;
+ fChecks = src.fChecks;
+ if (src.fSpoofData != NULL) {
+ fSpoofData = src.fSpoofData->addReference();
+ }
+ fAllowedCharsSet = static_cast<const UnicodeSet *>(src.fAllowedCharsSet->clone());
+ if (fAllowedCharsSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ fAllowedLocales = uprv_strdup(src.fAllowedLocales);
+}
+
+SpoofImpl::~SpoofImpl() {
+ fMagic = 0; // head off application errors by preventing use of
+ // of deleted objects.
+ if (fSpoofData != NULL) {
+ fSpoofData->removeReference(); // Will delete if refCount goes to zero.
+ }
+ delete fAllowedCharsSet;
+ uprv_free((void *)fAllowedLocales);
+}
+
+//
+// Incoming parameter check on Status and the SpoofChecker object
+// received from the C API.
+//
+const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (sc == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ };
+ SpoofImpl *This = (SpoofImpl *)sc;
+ if (This->fMagic != USPOOF_MAGIC ||
+ This->fSpoofData == NULL) {
+ status = U_INVALID_FORMAT_ERROR;
+ return NULL;
+ }
+ if (!SpoofData::validateDataVersion(This->fSpoofData->fRawData, status)) {
+ return NULL;
+ }
+ return This;
+}
+
+SpoofImpl *SpoofImpl::validateThis(USpoofChecker *sc, UErrorCode &status) {
+ return const_cast<SpoofImpl *>
+ (SpoofImpl::validateThis(const_cast<const USpoofChecker *>(sc), status));
+}
+
+
+
+//--------------------------------------------------------------------------------------
+//
+// confusableLookup() This is the heart of the confusable skeleton generation
+// implementation.
+//
+// Given a source character, produce the corresponding
+// replacement character(s)
+//
+//---------------------------------------------------------------------------------------
+int32_t SpoofImpl::confusableLookup(UChar32 inChar, int32_t tableMask, UChar *destBuf) const {
+
+ // Binary search the spoof data key table for the inChar
+ int32_t *low = fSpoofData->fCFUKeys;
+ int32_t *mid = NULL;
+ int32_t *limit = low + fSpoofData->fRawData->fCFUKeysSize;
+ UChar32 midc;
+ do {
+ int32_t delta = ((int32_t)(limit-low))/2;
+ mid = low + delta;
+ midc = *mid & 0x1fffff;
+ if (inChar == midc) {
+ goto foundChar;
+ } else if (inChar < midc) {
+ limit = mid;
+ } else {
+ low = mid;
+ }
+ } while (low < limit-1);
+ mid = low;
+ midc = *mid & 0x1fffff;
+ if (inChar != midc) {
+ // Char not found. It maps to itself.
+ int i = 0;
+ U16_APPEND_UNSAFE(destBuf, i, inChar)
+ return i;
+ }
+ foundChar:
+ int32_t keyFlags = *mid & 0xff000000;
+ if ((keyFlags & tableMask) == 0) {
+ // We found the right key char, but the entry doesn't pertain to the
+ // table we need. See if there is an adjacent key that does
+ if (keyFlags & USPOOF_KEY_MULTIPLE_VALUES) {
+ int32_t *altMid;
+ for (altMid = mid-1; (*altMid&0x00ffffff) == inChar; altMid--) {
+ keyFlags = *altMid & 0xff000000;
+ if (keyFlags & tableMask) {
+ mid = altMid;
+ goto foundKey;
+ }
+ }
+ for (altMid = mid+1; (*altMid&0x00ffffff) == inChar; altMid++) {
+ keyFlags = *altMid & 0xff000000;
+ if (keyFlags & tableMask) {
+ mid = altMid;
+ goto foundKey;
+ }
+ }
+ }
+ // No key entry for this char & table.
+ // The input char maps to itself.
+ int i = 0;
+ U16_APPEND_UNSAFE(destBuf, i, inChar)
+ return i;
+ }
+
+ foundKey:
+ int32_t stringLen = USPOOF_KEY_LENGTH_FIELD(keyFlags) + 1;
+ int32_t keyTableIndex = (int32_t)(mid - fSpoofData->fCFUKeys);
+
+ // Value is either a UChar (for strings of length 1) or
+ // an index into the string table (for longer strings)
+ uint16_t value = fSpoofData->fCFUValues[keyTableIndex];
+ if (stringLen == 1) {
+ destBuf[0] = value;
+ return 1;
+ }
+
+ // String length of 4 from the above lookup is used for all strings of length >= 4.
+ // For these, get the real length from the string lengths table,
+ // which maps string table indexes to lengths.
+ // All strings of the same length are stored contiguously in the string table.
+ // 'value' from the lookup above is the starting index for the desired string.
+
+ int32_t ix;
+ if (stringLen == 4) {
+ int32_t stringLengthsLimit = fSpoofData->fRawData->fCFUStringLengthsSize;
+ for (ix = 0; ix < stringLengthsLimit; ix++) {
+ if (fSpoofData->fCFUStringLengths[ix].fLastString >= value) {
+ stringLen = fSpoofData->fCFUStringLengths[ix].fStrLength;
+ break;
+ }
+ }
+ U_ASSERT(ix < stringLengthsLimit);
+ }
+
+ U_ASSERT(value + stringLen <= fSpoofData->fRawData->fCFUStringTableLen);
+ UChar *src = &fSpoofData->fCFUStrings[value];
+ for (ix=0; ix<stringLen; ix++) {
+ destBuf[ix] = src[ix];
+ }
+ return stringLen;
+}
+
+
+//---------------------------------------------------------------------------------------
+//
+// wholeScriptCheck()
+//
+// Input text is already normalized to NFD
+// Return the set of scripts, each of which can represent something that is
+// confusable with the input text. The script of the input text
+// is included; input consisting of characters from a single script will
+// always produce a result consisting of a set containing that script.
+//
+//---------------------------------------------------------------------------------------
+void SpoofImpl::wholeScriptCheck(
+ const UChar *text, int32_t length, ScriptSet *result, UErrorCode &status) const {
+
+ int32_t inputIdx = 0;
+ UChar32 c;
+
+ UTrie2 *table =
+ (fChecks & USPOOF_ANY_CASE) ? fSpoofData->fAnyCaseTrie : fSpoofData->fLowerCaseTrie;
+ result->setAll();
+ while (inputIdx < length) {
+ U16_NEXT(text, inputIdx, length, c);
+ uint32_t index = utrie2_get32(table, c);
+ if (index == 0) {
+ // No confusables in another script for this char.
+ // TODO: we should change the data to have sets with just the single script
+ // bit for the script of this char. Gets rid of this special case.
+ // Until then, grab the script from the char and intersect it with the set.
+ UScriptCode cpScript = uscript_getScript(c, &status);
+ U_ASSERT(cpScript > USCRIPT_INHERITED);
+ result->intersect(cpScript);
+ } else if (index == 1) {
+ // Script == Common or Inherited. Nothing to do.
+ } else {
+ result->intersect(fSpoofData->fScriptSets[index]);
+ }
+ }
+}
+
+
+void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
+ UnicodeSet allowedChars;
+ UnicodeSet *tmpSet = NULL;
+ const char *locStart = localesList;
+ const char *locEnd = NULL;
+ const char *localesListEnd = localesList + uprv_strlen(localesList);
+ int32_t localeListCount = 0; // Number of locales provided by caller.
+
+ // Loop runs once per locale from the localesList, a comma separated list of locales.
+ do {
+ locEnd = uprv_strchr(locStart, ',');
+ if (locEnd == NULL) {
+ locEnd = localesListEnd;
+ }
+ while (*locStart == ' ') {
+ locStart++;
+ }
+ const char *trimmedEnd = locEnd-1;
+ while (trimmedEnd > locStart && *trimmedEnd == ' ') {
+ trimmedEnd--;
+ }
+ if (trimmedEnd <= locStart) {
+ break;
+ }
+ const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart));
+ localeListCount++;
+
+ // We have one locale from the locales list.
+ // Add the script chars for this locale to the accumulating set of allowed chars.
+ // If the locale is no good, we will be notified back via status.
+ addScriptChars(locale, &allowedChars, status);
+ uprv_free((void *)locale);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ locStart = locEnd + 1;
+ } while (locStart < localesListEnd);
+
+ // If our caller provided an empty list of locales, we disable the allowed characters checking
+ if (localeListCount == 0) {
+ uprv_free((void *)fAllowedLocales);
+ fAllowedLocales = uprv_strdup("");
+ tmpSet = new UnicodeSet(0, 0x10ffff);
+ if (fAllowedLocales == NULL || tmpSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ tmpSet->freeze();
+ delete fAllowedCharsSet;
+ fAllowedCharsSet = tmpSet;
+ fChecks &= ~USPOOF_CHAR_LIMIT;
+ return;
+ }
+
+
+ // Add all common and inherited characters to the set of allowed chars.
+ UnicodeSet tempSet;
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status);
+ allowedChars.addAll(tempSet);
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status);
+ allowedChars.addAll(tempSet);
+
+ // If anything went wrong, we bail out without changing
+ // the state of the spoof checker.
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Store the updated spoof checker state.
+ tmpSet = static_cast<UnicodeSet *>(allowedChars.clone());
+ const char *tmpLocalesList = uprv_strdup(localesList);
+ if (tmpSet == NULL || tmpLocalesList == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_free((void *)fAllowedLocales);
+ fAllowedLocales = tmpLocalesList;
+ tmpSet->freeze();
+ delete fAllowedCharsSet;
+ fAllowedCharsSet = tmpSet;
+ fChecks |= USPOOF_CHAR_LIMIT;
+}
+
+
+const char * SpoofImpl::getAllowedLocales(UErrorCode &/*status*/) {
+ return fAllowedLocales;
+}
+
+
+// Given a locale (a language), add all the characters from all of the scripts used with that language
+// to the allowedChars UnicodeSet
+
+void SpoofImpl::addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status) {
+ UScriptCode scripts[30];
+
+ int32_t numScripts = uscript_getCode(locale, scripts, sizeof(scripts)/sizeof(UScriptCode), &status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (status == U_USING_DEFAULT_WARNING) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeSet tmpSet;
+ int32_t i;
+ for (i=0; i<numScripts; i++) {
+ tmpSet.applyIntPropertyValue(UCHAR_SCRIPT, scripts[i], status);
+ allowedChars->addAll(tmpSet);
+ }
+}
+
+
+int32_t SpoofImpl::scriptScan
+ (const UChar *text, int32_t length, int32_t &pos, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ int32_t inputIdx = 0;
+ UChar32 c;
+ int32_t scriptCount = 0;
+ UScriptCode lastScript = USCRIPT_INVALID_CODE;
+ UScriptCode sc = USCRIPT_INVALID_CODE;
+ while ((inputIdx < length || length == -1) && scriptCount < 2) {
+ U16_NEXT(text, inputIdx, length, c);
+ if (c == 0 && length == -1) {
+ break;
+ }
+ sc = uscript_getScript(c, &status);
+ if (sc == USCRIPT_COMMON || sc == USCRIPT_INHERITED || sc == USCRIPT_UNKNOWN) {
+ continue;
+ }
+
+ // Temporary fix: fold Japanese Hiragana and Katakana into Han.
+ // Names are allowed to mix these scripts.
+ // A more general solution will follow later for characters that are
+ // used with multiple scripts.
+
+ if (sc == USCRIPT_HIRAGANA || sc == USCRIPT_KATAKANA || sc == USCRIPT_HANGUL) {
+ sc = USCRIPT_HAN;
+ }
+
+ if (sc != lastScript) {
+ scriptCount++;
+ lastScript = sc;
+ }
+ }
+ if (scriptCount == 2) {
+ pos = inputIdx;
+ }
+ return scriptCount;
+}
+
+
+// Convert a text format hex number. Utility function used by builder code. Static.
+// Input: UChar *string text. Output: a UChar32
+// Input has been pre-checked, and will have no non-hex chars.
+// The number must fall in the code point range of 0..0x10ffff
+// Static Function.
+UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ U_ASSERT(limit-start > 0);
+ uint32_t val = 0;
+ int i;
+ for (i=start; i<limit; i++) {
+ int digitVal = s[i] - 0x30;
+ if (digitVal>9) {
+ digitVal = 0xa + (s[i] - 0x41); // Upper Case 'A'
+ }
+ if (digitVal>15) {
+ digitVal = 0xa + (s[i] - 0x61); // Lower Case 'a'
+ }
+ U_ASSERT(digitVal <= 0xf);
+ val <<= 4;
+ val += digitVal;
+ }
+ if (val > 0x10ffff) {
+ status = U_PARSE_ERROR;
+ val = 0;
+ }
+ return (UChar32)val;
+}
+
+
+
+//----------------------------------------------------------------------------------------------
+//
+// class SpoofData Implementation
+//
+//----------------------------------------------------------------------------------------------
+
+
+UBool SpoofData::validateDataVersion(const SpoofDataHeader *rawData, UErrorCode &status) {
+ if (U_FAILURE(status) ||
+ rawData == NULL ||
+ rawData->fMagic != USPOOF_MAGIC ||
+ rawData->fFormatVersion[0] > 1 ||
+ rawData->fFormatVersion[1] > 0) {
+ status = U_INVALID_FORMAT_ERROR;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//
+// SpoofData::getDefault() - return a wrapper around the spoof data that is
+// baked into the default ICU data.
+//
+SpoofData *SpoofData::getDefault(UErrorCode &status) {
+ // TODO: Cache it. Lazy create, keep until cleanup.
+
+ UDataMemory *udm = udata_open(NULL, "cfu", "confusables", &status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ SpoofData *This = new SpoofData(udm, status);
+ if (U_FAILURE(status)) {
+ delete This;
+ return NULL;
+ }
+ if (This == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return This;
+}
+
+
+SpoofData::SpoofData(UDataMemory *udm, UErrorCode &status)
+{
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fRawData = reinterpret_cast<SpoofDataHeader *>
+ ((char *)(udm->pHeader) + udm->pHeader->dataHeader.headerSize);
+ fUDM = udm;
+ validateDataVersion(fRawData, status);
+ initPtrs(status);
+}
+
+
+SpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status)
+{
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if ((size_t)length < sizeof(SpoofDataHeader)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ void *ncData = const_cast<void *>(data);
+ fRawData = static_cast<SpoofDataHeader *>(ncData);
+ if (length < fRawData->fLength) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ validateDataVersion(fRawData, status);
+ initPtrs(status);
+}
+
+
+// Spoof Data constructor for use from data builder.
+// Initializes a new, empty data area that will be populated later.
+SpoofData::SpoofData(UErrorCode &status) {
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fDataOwned = true;
+ fRefCount = 1;
+
+ // The spoof header should already be sized to be a multiple of 16 bytes.
+ // Just in case it's not, round it up.
+ uint32_t initialSize = (sizeof(SpoofDataHeader) + 15) & ~15;
+ U_ASSERT(initialSize == sizeof(SpoofDataHeader));
+
+ fRawData = static_cast<SpoofDataHeader *>(uprv_malloc(initialSize));
+ fMemLimit = initialSize;
+ if (fRawData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memset(fRawData, 0, initialSize);
+
+ fRawData->fMagic = USPOOF_MAGIC;
+ fRawData->fFormatVersion[0] = 1;
+ fRawData->fFormatVersion[1] = 0;
+ fRawData->fFormatVersion[2] = 0;
+ fRawData->fFormatVersion[3] = 0;
+ initPtrs(status);
+}
+
+// reset() - initialize all fields.
+// Should be updated if any new fields are added.
+// Called by constructors to put things in a known initial state.
+void SpoofData::reset() {
+ fRawData = NULL;
+ fDataOwned = FALSE;
+ fUDM = NULL;
+ fMemLimit = 0;
+ fRefCount = 1;
+ fCFUKeys = NULL;
+ fCFUValues = NULL;
+ fCFUStringLengths = NULL;
+ fCFUStrings = NULL;
+ fAnyCaseTrie = NULL;
+ fLowerCaseTrie = NULL;
+ fScriptSets = NULL;
+}
+
+
+// SpoofData::initPtrs()
+// Initialize the pointers to the various sections of the raw data.
+//
+// This function is used both during the Trie building process (multiple
+// times, as the individual data sections are added), and
+// during the opening of a Spoof Checker from prebuilt data.
+//
+// The pointers for non-existent data sections (identified by an offset of 0)
+// are set to NULL.
+//
+// Note: During building the data, adding each new data section
+// reallocs the raw data area, which likely relocates it, which
+// in turn requires reinitializing all of the pointers into it, hence
+// multiple calls to this function during building.
+//
+void SpoofData::initPtrs(UErrorCode &status) {
+ fCFUKeys = NULL;
+ fCFUValues = NULL;
+ fCFUStringLengths = NULL;
+ fCFUStrings = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fRawData->fCFUKeys != 0) {
+ fCFUKeys = (int32_t *)((char *)fRawData + fRawData->fCFUKeys);
+ }
+ if (fRawData->fCFUStringIndex != 0) {
+ fCFUValues = (uint16_t *)((char *)fRawData + fRawData->fCFUStringIndex);
+ }
+ if (fRawData->fCFUStringLengths != 0) {
+ fCFUStringLengths = (SpoofStringLengthsElement *)((char *)fRawData + fRawData->fCFUStringLengths);
+ }
+ if (fRawData->fCFUStringTable != 0) {
+ fCFUStrings = (UChar *)((char *)fRawData + fRawData->fCFUStringTable);
+ }
+
+ if (fAnyCaseTrie == NULL && fRawData->fAnyCaseTrie != 0) {
+ fAnyCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
+ (char *)fRawData + fRawData->fAnyCaseTrie, fRawData->fAnyCaseTrieLength, NULL, &status);
+ }
+ if (fLowerCaseTrie == NULL && fRawData->fLowerCaseTrie != 0) {
+ fLowerCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
+ (char *)fRawData + fRawData->fLowerCaseTrie, fRawData->fLowerCaseTrieLength, NULL, &status);
+ }
+
+ if (fRawData->fScriptSets != 0) {
+ fScriptSets = (ScriptSet *)((char *)fRawData + fRawData->fScriptSets);
+ }
+}
+
+
+SpoofData::~SpoofData() {
+ utrie2_close(fAnyCaseTrie);
+ fAnyCaseTrie = NULL;
+ utrie2_close(fLowerCaseTrie);
+ fLowerCaseTrie = NULL;
+ if (fDataOwned) {
+ uprv_free(fRawData);
+ }
+ fRawData = NULL;
+ if (fUDM != NULL) {
+ udata_close(fUDM);
+ }
+ fUDM = NULL;
+}
+
+
+void SpoofData::removeReference() {
+ if (umtx_atomic_dec(&fRefCount) == 0) {
+ delete this;
+ }
+}
+
+
+SpoofData *SpoofData::addReference() {
+ umtx_atomic_inc(&fRefCount);
+ return this;
+}
+
+
+void *SpoofData::reserveSpace(int32_t numBytes, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (!fDataOwned) {
+ U_ASSERT(FALSE);
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return NULL;
+ }
+
+ numBytes = (numBytes + 15) & ~15; // Round up to a multiple of 16
+ uint32_t returnOffset = fMemLimit;
+ fMemLimit += numBytes;
+ fRawData = static_cast<SpoofDataHeader *>(uprv_realloc(fRawData, fMemLimit));
+ fRawData->fLength = fMemLimit;
+ uprv_memset((char *)fRawData + returnOffset, 0, numBytes);
+ initPtrs(status);
+ return (char *)fRawData + returnOffset;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// ScriptSet implementation
+//
+//----------------------------------------------------------------------------
+ScriptSet::ScriptSet() {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] = 0;
+ }
+}
+
+ScriptSet::~ScriptSet() {
+}
+
+UBool ScriptSet::operator == (const ScriptSet &other) {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ if (bits[i] != other.bits[i]) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void ScriptSet::Union(UScriptCode script) {
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ U_ASSERT(index < sizeof(bits)*4);
+ bits[index] |= bit;
+}
+
+
+void ScriptSet::Union(const ScriptSet &other) {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] |= other.bits[i];
+ }
+}
+
+void ScriptSet::intersect(const ScriptSet &other) {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] &= other.bits[i];
+ }
+}
+
+void ScriptSet::intersect(UScriptCode script) {
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ U_ASSERT(index < sizeof(bits)*4);
+ uint32_t i;
+ for (i=0; i<index; i++) {
+ bits[i] = 0;
+ }
+ bits[index] &= bit;
+ for (i=index+1; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] = 0;
+ }
+}
+
+
+ScriptSet & ScriptSet::operator =(const ScriptSet &other) {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] = other.bits[i];
+ }
+ return *this;
+}
+
+
+void ScriptSet::setAll() {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] = 0xffffffffu;
+ }
+}
+
+
+void ScriptSet::resetAll() {
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ bits[i] = 0;
+ }
+}
+
+int32_t ScriptSet::countMembers() {
+ // This bit counter is good for sparse numbers of '1's, which is
+ // very much the case that we will usually have.
+ int32_t count = 0;
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
+ uint32_t x = bits[i];
+ while (x > 0) {
+ count++;
+ x &= (x - 1); // and off the least significant one bit.
+ }
+ }
+ return count;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// NFDBuffer Implementation.
+//
+//-----------------------------------------------------------------------------
+
+NFDBuffer::NFDBuffer(const UChar *text, int32_t length, UErrorCode &status) {
+ fNormalizedText = NULL;
+ fNormalizedTextLength = 0;
+ fOriginalText = text;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fNormalizedText = fSmallBuf;
+ fNormalizedTextLength = unorm_normalize(
+ text, length, UNORM_NFD, 0, fNormalizedText, USPOOF_STACK_BUFFER_SIZE, &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ fNormalizedText = (UChar *)uprv_malloc((fNormalizedTextLength+1)*sizeof(UChar));
+ if (fNormalizedText == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ fNormalizedTextLength = unorm_normalize(text, length, UNORM_NFD, 0,
+ fNormalizedText, fNormalizedTextLength+1, &status);
+ }
+ }
+}
+
+
+NFDBuffer::~NFDBuffer() {
+ if (fNormalizedText != fSmallBuf) {
+ uprv_free(fNormalizedText);
+ }
+ fNormalizedText = 0;
+}
+
+const UChar *NFDBuffer::getBuffer() {
+ return fNormalizedText;
+}
+
+int32_t NFDBuffer::getLength() {
+ return fNormalizedTextLength;
+}
+
+
+
+
+
+U_NAMESPACE_END
+
+U_NAMESPACE_USE
+
+//-----------------------------------------------------------------------------
+//
+// uspoof_swap - byte swap and char encoding swap of spoof data
+//
+//-----------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+ UErrorCode *status) {
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+ if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ //
+ // Check that the data header is for spoof data.
+ // (Header contents are defined in gencfu.cpp)
+ //
+ const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
+ if(!( pInfo->dataFormat[0]==0x43 && /* dataFormat="Cfu " */
+ pInfo->dataFormat[1]==0x66 &&
+ pInfo->dataFormat[2]==0x75 &&
+ pInfo->dataFormat[3]==0x20 &&
+ pInfo->formatVersion[0]==1 )) {
+ udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x "
+ "(format version %02x %02x %02x %02x) is not recognized\n",
+ pInfo->dataFormat[0], pInfo->dataFormat[1],
+ pInfo->dataFormat[2], pInfo->dataFormat[3],
+ pInfo->formatVersion[0], pInfo->formatVersion[1],
+ pInfo->formatVersion[2], pInfo->formatVersion[3]);
+ *status=U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ //
+ // Swap the data header. (This is the generic ICU Data Header, not the uspoof Specific
+ // header). This swap also conveniently gets us
+ // the size of the ICU d.h., which lets us locate the start
+ // of the uspoof specific data.
+ //
+ int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
+
+
+ //
+ // Get the Spoof Data Header, and check that it appears to be OK.
+ //
+ //
+ const uint8_t *inBytes =(const uint8_t *)inData+headerSize;
+ SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes;
+ if (ds->readUInt32(spoofDH->fMagic) != USPOOF_MAGIC ||
+ ds->readUInt32(spoofDH->fLength) < sizeof(SpoofDataHeader))
+ {
+ udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n");
+ *status=U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ //
+ // Prefight operation? Just return the size
+ //
+ int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength);
+ int32_t totalSize = headerSize + spoofDataLength;
+ if (length < 0) {
+ return totalSize;
+ }
+
+ //
+ // Check that length passed in is consistent with length from Spoof data header.
+ //
+ if (length < totalSize) {
+ udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n",
+ spoofDataLength);
+ *status=U_INDEX_OUTOFBOUNDS_ERROR;
+ return 0;
+ }
+
+
+ //
+ // Swap the Data. Do the data itself first, then the Spoof Data Header, because
+ // we need to reference the header to locate the data, and an
+ // inplace swap of the header leaves it unusable.
+ //
+ uint8_t *outBytes = (uint8_t *)outData + headerSize;
+ SpoofDataHeader *outputDH = (SpoofDataHeader *)outBytes;
+
+ int32_t sectionStart;
+ int32_t sectionLength;
+
+ //
+ // If not swapping in place, zero out the output buffer before starting.
+ // Gaps may exist between the individual sections, and these must be zeroed in
+ // the output buffer. The simplest way to do that is to just zero the whole thing.
+ //
+ if (inBytes != outBytes) {
+ uprv_memset(outBytes, 0, spoofDataLength);
+ }
+
+ // Confusables Keys Section (fCFUKeys)
+ sectionStart = ds->readUInt32(spoofDH->fCFUKeys);
+ sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4;
+ ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Index Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringIndex);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Table Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringTable);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Lengths Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringLengths);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringLengthsSize) * 4;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // Any Case Trie
+ sectionStart = ds->readUInt32(spoofDH->fAnyCaseTrie);
+ sectionLength = ds->readUInt32(spoofDH->fAnyCaseTrieLength);
+ utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // Lower Case Trie
+ sectionStart = ds->readUInt32(spoofDH->fLowerCaseTrie);
+ sectionLength = ds->readUInt32(spoofDH->fLowerCaseTrieLength);
+ utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // Script Sets. The data is an array of int32_t
+ sectionStart = ds->readUInt32(spoofDH->fScriptSets);
+ sectionLength = ds->readUInt32(spoofDH->fScriptSetsLength) * sizeof(ScriptSet);
+ ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // And, last, swap the header itself.
+ // int32_t fMagic // swap this
+ // uint8_t fFormatVersion[4] // Do not swap this, just copy
+ // int32_t fLength and all the rest // Swap the rest, all is 32 bit stuff.
+ //
+ uint32_t magic = ds->readUInt32(spoofDH->fMagic);
+ ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
+
+ if (outputDH->fFormatVersion != spoofDH->fFormatVersion) {
+ uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
+ }
+ // swap starting at fLength
+ ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status);
+
+ return totalSize;
+}
+
+#endif
+
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.h b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.h
new file mode 100644
index 00000000000..20b2bc30a90
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_impl.h
@@ -0,0 +1,407 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+*
+* uspoof_impl.h
+*
+* Implemenation header for spoof detection
+*
+*/
+
+#ifndef USPOOFIM_H
+#define USPOOFIM_H
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "utrie2.h"
+#include "unicode/uscript.h"
+#include "unicode/udata.h"
+
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+// The maximium length (in UTF-16 UChars) of the skeleton replacement string resulting from
+// a single input code point. This is function of the unicode.org data.
+#define USPOOF_MAX_SKELETON_EXPANSION 20
+
+// The default stack buffer size for copies or conversions or normalizations
+// of input strings being checked. (Used in multiple places.)
+#define USPOOF_STACK_BUFFER_SIZE 100
+
+// Magic number for sanity checking spoof data.
+#define USPOOF_MAGIC 0x3845fdef
+
+class SpoofData;
+struct SpoofDataHeader;
+struct SpoofStringLengthsElement;
+class ScriptSet;
+
+/**
+ * Class SpoofImpl corresponds directly to the plain C API opaque type
+ * USpoofChecker. One can be cast to the other.
+ */
+class SpoofImpl : public UObject {
+public:
+ SpoofImpl(SpoofData *data, UErrorCode &status);
+ SpoofImpl();
+ virtual ~SpoofImpl();
+
+ /** Copy constructor, used by the user level uspoof_clone() function.
+ */
+ SpoofImpl(const SpoofImpl &src, UErrorCode &status);
+
+ static SpoofImpl *validateThis(USpoofChecker *sc, UErrorCode &status);
+ static const SpoofImpl *validateThis(const USpoofChecker *sc, UErrorCode &status);
+
+ /** Get the confusable skeleton transform for a single code point.
+ * The result is a string with a length between 1 and 18.
+ * @param tableMask bit flag specifying which confusable table to use.
+ * One of USPOOF_SL_TABLE_FLAG, USPOOF_MA_TABLE_FLAG, etc.
+ * @return The length in UTF-16 code units of the substition string.
+ */
+ int32_t confusableLookup(UChar32 inChar, int32_t tableMask, UChar *destBuf) const;
+
+ /** Set and Get AllowedLocales, implementations of the corresponding API */
+ void setAllowedLocales(const char *localesList, UErrorCode &status);
+ const char * getAllowedLocales(UErrorCode &status);
+
+ // Add (union) to the UnicodeSet all of the characters for the scripts used for
+ // the specified locale. Part of the implementation of setAllowedLocales.
+ void addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status);
+
+
+ /** parse a hex number. Untility used by the builders. */
+ static UChar32 ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status);
+
+ // Implementation for Whole Script tests.
+ // Return the test bit flag to be ORed into the eventual user return value
+ // if a Spoof opportunity is detected.
+ void wholeScriptCheck(
+ const UChar *text, int32_t length, ScriptSet *result, UErrorCode &status) const;
+
+ /** Scan a string to determine how many scripts it includes.
+ * Ignore characters with script=Common and scirpt=Inherited.
+ * @param text The UChar text to be scanned
+ * @param length The length of the input text, -1 for nul termintated.
+ * @param pos An out parameter, set to the first input postion at which
+ * a second script was encountered, ignoring Common and Inherited.
+ * @param status For errors.
+ * @return the number of (non-common,inherited) scripts encountered,
+ * clipped to a max of two.
+ */
+ int32_t scriptScan(const UChar *text, int32_t length, int32_t &pos, UErrorCode &status) const;
+
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+
+ //
+ // Data Members
+ //
+
+ int32_t fMagic; // Internal sanity check.
+ int32_t fChecks; // Bit vector of checks to perform.
+
+ SpoofData *fSpoofData;
+
+ const UnicodeSet *fAllowedCharsSet; // The UnicodeSet of allowed characters.
+ // for this Spoof Checker. Defaults to all chars.
+
+ const char *fAllowedLocales; // The list of allowed locales.
+};
+
+
+
+//
+// Confusable Mappings Data Structures
+//
+// For the confusable data, we are essentially implementing a map,
+// key: a code point
+// value: a string. Most commonly one char in length, but can be more.
+//
+// The keys are stored as a sorted array of 32 bit ints.
+// bits 0-23 a code point value
+// bits 24-31 flags
+// 24: 1 if entry applies to SL table
+// 25: 1 if entry applies to SA table
+// 26: 1 if entry applies to ML table
+// 27: 1 if entry applies to MA table
+// 28: 1 if there are multiple entries for this code point.
+// 29-30: length of value string, in UChars.
+// values are (1, 2, 3, other)
+// The key table is sorted in ascending code point order. (not on the
+// 32 bit int value, the flag bits do not participate in the sorting.)
+//
+// Lookup is done by means of a binary search in the key table.
+//
+// The corresponding values are kept in a parallel array of 16 bit ints.
+// If the value string is of length 1, it is literally in the value array.
+// For longer strings, the value array contains an index into the strings table.
+//
+// String Table:
+// The strings table contains all of the value strings (those of length two or greater)
+// concatentated together into one long UChar (UTF-16) array.
+//
+// The array is arranged by length of the strings - all strings of the same length
+// are stored together. The sections are ordered by length of the strings -
+// all two char strings first, followed by all of the three Char strings, etc.
+//
+// There is no nul character or other mark between adjacent strings.
+//
+// String Lengths table
+// The length of strings from 1 to 3 is flagged in the key table.
+// For strings of length 4 or longer, the string length table provides a
+// mapping between an index into the string table and the corresponding length.
+// Strings of these lengths are rare, so lookup time is not an issue.
+// Each entry consists of
+// uint16_t index of the _last_ string with this length
+// uint16_t the length
+//
+
+// Flag bits in the Key entries
+#define USPOOF_SL_TABLE_FLAG (1<<24)
+#define USPOOF_SA_TABLE_FLAG (1<<25)
+#define USPOOF_ML_TABLE_FLAG (1<<26)
+#define USPOOF_MA_TABLE_FLAG (1<<27)
+#define USPOOF_KEY_MULTIPLE_VALUES (1<<28)
+#define USPOOF_KEY_LENGTH_SHIFT 29
+#define USPOOF_KEY_LENGTH_FIELD(x) (((x)>>29) & 3)
+
+
+struct SpoofStringLengthsElement {
+ uint16_t fLastString; // index in string table of last string with this length
+ uint16_t fStrLength; // Length of strings
+};
+
+
+//-------------------------------------------------------------------------------
+//
+// ScriptSet - Wrapper class for the Script code bit sets that are part of the
+// whole script confusable data.
+//
+// This class is used both at data build and at run time.
+// The constructor is only used at build time.
+// At run time, just point at the prebuilt data and go.
+//
+//-------------------------------------------------------------------------------
+class ScriptSet: public UMemory {
+ public:
+ ScriptSet();
+ ~ScriptSet();
+
+ UBool operator == (const ScriptSet &other);
+ ScriptSet & operator = (const ScriptSet &other);
+
+ void Union(const ScriptSet &other);
+ void Union(UScriptCode script);
+ void intersect(const ScriptSet &other);
+ void intersect(UScriptCode script);
+ void setAll();
+ void resetAll();
+ int32_t countMembers();
+
+ private:
+ uint32_t bits[6];
+};
+
+
+
+
+//-------------------------------------------------------------------------------
+//
+// NFDBuffer A little class to handle the NFD normalization that is
+// needed on incoming identifiers to be checked.
+// Takes care of buffer handling and normalization
+//
+// Instances of this class are intended to be stack-allocated.
+//
+// TODO: how to map position offsets back to user values?
+//
+//--------------------------------------------------------------------------------
+class NFDBuffer: public UMemory {
+public:
+ NFDBuffer(const UChar *text, int32_t length, UErrorCode &status);
+ ~NFDBuffer();
+ const UChar *getBuffer();
+ int32_t getLength();
+
+ private:
+ const UChar *fOriginalText;
+ UChar *fNormalizedText;
+ int32_t fNormalizedTextLength;
+ UChar fSmallBuf[USPOOF_STACK_BUFFER_SIZE];
+};
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+//
+// SpoofData
+//
+// A small class that wraps the raw (usually memory mapped) spoof data.
+// Serves two primary functions:
+// 1. Convenience. Contains real pointers to the data, to avoid dealing with
+// the offsets in the raw data.
+// 2. Reference counting. When a spoof checker is cloned, the raw data is shared
+// and must be retained until all checkers using the data are closed.
+// Nothing in this struct includes state that is specific to any particular
+// USpoofDetector object.
+//
+//---------------------------------------------------------------------------------------
+class SpoofData: public UMemory {
+ public:
+ static SpoofData *getDefault(UErrorCode &status); // Load standard ICU spoof data.
+ SpoofData(UErrorCode &status); // Create new spoof data wrapper.
+ // Only used when building new data from rules.
+
+ // Constructor for use when creating from prebuilt default data.
+ // A UDataMemory is what the ICU internal data loading functions provide.
+ // The udm is adopted by the SpoofData.
+ SpoofData(UDataMemory *udm, UErrorCode &status);
+
+ // Constructor for use when creating from serialized data.
+ //
+ SpoofData(const void *serializedData, int32_t length, UErrorCode &status);
+
+ // Check raw Spoof Data Version compatibility.
+ // Return TRUE it looks good.
+ static UBool validateDataVersion(const SpoofDataHeader *rawData, UErrorCode &status);
+ ~SpoofData(); // Destructor not normally used.
+ // Use removeReference() instead.
+ // Reference Counting functions.
+ // Clone of a user-level spoof detector increments the ref count on the data.
+ // Close of a user-level spoof detector decrements the ref count.
+ // If the data is owned by us, it will be deleted when count goes to zero.
+ SpoofData *addReference();
+ void removeReference();
+
+ // Reserve space in the raw data. For use by builder when putting together a
+ // new set of data. Init the new storage to zero, to prevent inconsistent
+ // results if it is not all otherwise set by the requester.
+ // Return:
+ // pointer to the new space that was added by this function.
+ void *reserveSpace(int32_t numBytes, UErrorCode &status);
+
+ // initialize the pointers from this object to the raw data.
+ void initPtrs(UErrorCode &status);
+
+ // Reset all fields to an initial state.
+ // Called from the top of all constructors.
+ void reset();
+
+ SpoofDataHeader *fRawData; // Ptr to the raw memory-mapped data
+ UBool fDataOwned; // True if the raw data is owned, and needs
+ // to be deleted when refcount goes to zero.
+ UDataMemory *fUDM; // If not NULL, our data came from a
+ // UDataMemory, which we must close when
+ // we are done.
+
+ uint32_t fMemLimit; // Limit of available raw data space
+ int32_t fRefCount;
+
+ // Confusable data
+ int32_t *fCFUKeys;
+ uint16_t *fCFUValues;
+ SpoofStringLengthsElement *fCFUStringLengths;
+ UChar *fCFUStrings;
+
+ // Whole Script Confusable Data
+ UTrie2 *fAnyCaseTrie;
+ UTrie2 *fLowerCaseTrie;
+ ScriptSet *fScriptSets;
+ };
+
+
+//---------------------------------------------------------------------------------------
+//
+// Raw Binary Data Formats, as loaded from the ICU data file,
+// or as built by the builder.
+//
+//---------------------------------------------------------------------------------------
+struct SpoofDataHeader {
+ int32_t fMagic; // (0x3845fdef)
+ uint8_t fFormatVersion[4]; // Data Format. Same as the value in struct UDataInfo
+ // if there is one associated with this data.
+ int32_t fLength; // Total lenght in bytes of this spoof data,
+ // including all sections, not just the header.
+
+ // The following four sections refer to data representing the confusable data
+ // from the Unicode.org data from "confusables.txt"
+
+ int32_t fCFUKeys; // byte offset to Keys table (from SpoofDataHeader *)
+ int32_t fCFUKeysSize; // number of entries in keys table (32 bits each)
+
+ // TODO: change name to fCFUValues, for consistency.
+ int32_t fCFUStringIndex; // byte offset to String Indexes table
+ int32_t fCFUStringIndexSize; // number of entries in String Indexes table (16 bits each)
+ // (number of entries must be same as in Keys table
+
+ int32_t fCFUStringTable; // byte offset of String table
+ int32_t fCFUStringTableLen; // length of string table (in 16 bit UChars)
+
+ int32_t fCFUStringLengths; // byte offset to String Lengths table
+ int32_t fCFUStringLengthsSize; // number of entries in lengths table. (2 x 16 bits each)
+
+
+ // The following sections are for data from confusablesWholeScript.txt
+
+ int32_t fAnyCaseTrie; // byte offset to the serialized Any Case Trie
+ int32_t fAnyCaseTrieLength; // Length (bytes) of the serialized Any Case Trie
+
+ int32_t fLowerCaseTrie; // byte offset to the serialized Lower Case Trie
+ int32_t fLowerCaseTrieLength; // Length (bytes) of the serialized Lower Case Trie
+
+ int32_t fScriptSets; // byte offset to array of ScriptSets
+ int32_t fScriptSetsLength; // Number of ScriptSets (24 bytes each)
+
+
+ // The following sections are for data from xidmodifications.txt
+
+
+ int32_t unused[15]; // Padding, Room for Expansion
+
+ };
+
+
+
+
+//
+// Structure for the Whole Script Confusable Data
+// See Unicode UAX-39, Unicode Security Mechanisms, for a description of the
+// Whole Script confusable data
+//
+// The data provides mappings from code points to a set of scripts
+// that contain characters that might be confused with the code point.
+// There are two mappings, one for lower case only, and one for characters
+// of any case.
+//
+// The actual data consists of a utrie2 to map from a code point to an offset,
+// and an array of UScriptSets (essentially bit maps) that is indexed
+// by the offsets obtained from the Trie.
+//
+//
+
+
+U_NAMESPACE_END
+#endif /* XP_CPLUSPLUS */
+
+/**
+ * Endianness swap function for binary spoof data.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+ UErrorCode *status);
+
+
+#endif
+
+#endif /* USPOOFIM_H */
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.cpp
new file mode 100644
index 00000000000..2417512de2b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.cpp
@@ -0,0 +1,431 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2011, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+* file name: uspoof_wsconf.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2009Jan05 (refactoring earlier files)
+* created by: Andy Heninger
+*
+* Internal functions for compililing Whole Script confusable source data
+* into its binary (runtime) form. The binary data format is described
+* in uspoof_impl.h
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/unorm.h"
+#include "unicode/uregex.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "uspoof_impl.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "uassert.h"
+#include "uspoof_wsconf.h"
+
+U_NAMESPACE_USE
+
+
+// Regular expression for parsing a line from the Unicode file confusablesWholeScript.txt
+// Example Lines:
+// 006F ; Latn; Deva; A # (o) LATIN SMALL LETTER O
+// 0048..0049 ; Latn; Grek; A # [2] (H..I) LATIN CAPITAL LETTER H..LATIN CAPITAL LETTER I
+// | | | |
+// | | | |---- Which table, Any Case or Lower Case (A or L)
+// | | |----------Target script. We need this.
+// | |----------------Src script. Should match the script of the source
+// | code points. Beyond checking that, we don't keep it.
+// |--------------------------------Source code points or range.
+//
+// The expression will match _all_ lines, including erroneous lines.
+// The result of the parse is returned via the contents of the (match) groups.
+static const char *parseExp =
+ "(?m)" // Multi-line mode
+ "^([ \\t]*(?:#.*?)?)$" // A blank or comment line. Matches Group 1.
+ "|^(?:" // OR
+ "\\s*([0-9A-F]{4,})(?:..([0-9A-F]{4,}))?\\s*;" // Code point range. Groups 2 and 3.
+ "\\s*([A-Za-z]+)\\s*;" // The source script. Group 4.
+ "\\s*([A-Za-z]+)\\s*;" // The target script. Group 5.
+ "\\s*(?:(A)|(L))" // The table A or L. Group 6 or 7
+ "[ \\t]*(?:#.*?)?" // Trailing commment
+ ")$|" // OR
+ "^(.*?)$"; // An error line. Group 8.
+ // Any line not matching the preceding
+ // parts of the expression.will match
+ // this, and thus be flagged as an error
+
+
+// Extract a regular expression match group into a char * string.
+// The group must contain only invariant characters.
+// Used for script names
+//
+static void extractGroup(
+ URegularExpression *e, int32_t group, char *destBuf, int32_t destCapacity, UErrorCode &status) {
+
+ UChar ubuf[50];
+ ubuf[0] = 0;
+ destBuf[0] = 0;
+ int32_t len = uregex_group(e, group, ubuf, 50, &status);
+ if (U_FAILURE(status) || len == -1 || len >= destCapacity) {
+ return;
+ }
+ UnicodeString s(FALSE, ubuf, len); // Aliasing constructor
+ s.extract(0, len, destBuf, destCapacity, US_INV);
+}
+
+
+
+// Build the Whole Script Confusable data
+//
+// TODO: Reorganize. Either get rid of the WSConfusableDataBuilder class,
+// because everything is local to this one build function anyhow,
+// OR
+// break this function into more reasonably sized pieces, with
+// state in WSConfusableDataBuilder.
+//
+void buildWSConfusableData(SpoofImpl *spImpl, const char * confusablesWS,
+ int32_t confusablesWSLen, UParseError *pe, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ URegularExpression *parseRegexp = NULL;
+ int32_t inputLen = 0;
+ UChar *input = NULL;
+ int32_t lineNum = 0;
+
+ UVector *scriptSets = NULL;
+ uint32_t rtScriptSetsCount = 2;
+
+ UTrie2 *anyCaseTrie = NULL;
+ UTrie2 *lowerCaseTrie = NULL;
+
+ anyCaseTrie = utrie2_open(0, 0, &status);
+ lowerCaseTrie = utrie2_open(0, 0, &status);
+
+ UnicodeString pattern(parseExp, -1, US_INV);
+
+ // The scriptSets vector provides a mapping from TRIE values to the set of scripts.
+ //
+ // Reserved TRIE values:
+ // 0: Code point has no whole script confusables.
+ // 1: Code point is of script Common or Inherited.
+ // These code points do not participate in whole script confusable detection.
+ // (This is logically equivalent to saying that they contain confusables in
+ // all scripts)
+ //
+ // Because Trie values are indexes into the ScriptSets vector, pre-fill
+ // vector positions 0 and 1 to avoid conflicts with the reserved values.
+
+ scriptSets = new UVector(status);
+ if (scriptSets == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ scriptSets->addElement((void *)NULL, status);
+ scriptSets->addElement((void *)NULL, status);
+
+ // Convert the user input data from UTF-8 to UChar (UTF-16)
+ u_strFromUTF8(NULL, 0, &inputLen, confusablesWS, confusablesWSLen, &status);
+ if (status != U_BUFFER_OVERFLOW_ERROR) {
+ goto cleanup;
+ }
+ status = U_ZERO_ERROR;
+ input = static_cast<UChar *>(uprv_malloc((inputLen+1) * sizeof(UChar)));
+ if (input == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ u_strFromUTF8(input, inputLen+1, NULL, confusablesWS, confusablesWSLen, &status);
+
+ parseRegexp = uregex_open(pattern.getBuffer(), pattern.length(), 0, NULL, &status);
+
+ // Zap any Byte Order Mark at the start of input. Changing it to a space is benign
+ // given the syntax of the input.
+ if (*input == 0xfeff) {
+ *input = 0x20;
+ }
+
+ // Parse the input, one line per iteration of this loop.
+ uregex_setText(parseRegexp, input, inputLen, &status);
+ while (uregex_findNext(parseRegexp, &status)) {
+ lineNum++;
+ if (uregex_start(parseRegexp, 1, &status) >= 0) {
+ // this was a blank or comment line.
+ continue;
+ }
+ if (uregex_start(parseRegexp, 8, &status) >= 0) {
+ // input file syntax error.
+ status = U_PARSE_ERROR;
+ goto cleanup;
+ }
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ // Pick up the start and optional range end code points from the parsed line.
+ UChar32 startCodePoint = SpoofImpl::ScanHex(
+ input, uregex_start(parseRegexp, 2, &status), uregex_end(parseRegexp, 2, &status), status);
+ UChar32 endCodePoint = startCodePoint;
+ if (uregex_start(parseRegexp, 3, &status) >=0) {
+ endCodePoint = SpoofImpl::ScanHex(
+ input, uregex_start(parseRegexp, 3, &status), uregex_end(parseRegexp, 3, &status), status);
+ }
+
+ // Extract the two script names from the source line. We need these in an 8 bit
+ // default encoding (will be EBCDIC on IBM mainframes) in order to pass them on
+ // to the ICU u_getPropertyValueEnum() function. Ugh.
+ char srcScriptName[20];
+ char targScriptName[20];
+ extractGroup(parseRegexp, 4, srcScriptName, sizeof(srcScriptName), status);
+ extractGroup(parseRegexp, 5, targScriptName, sizeof(targScriptName), status);
+ UScriptCode srcScript =
+ static_cast<UScriptCode>(u_getPropertyValueEnum(UCHAR_SCRIPT, srcScriptName));
+ UScriptCode targScript =
+ static_cast<UScriptCode>(u_getPropertyValueEnum(UCHAR_SCRIPT, targScriptName));
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ if (srcScript == USCRIPT_INVALID_CODE || targScript == USCRIPT_INVALID_CODE) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto cleanup;
+ }
+
+ // select the table - (A) any case or (L) lower case only
+ UTrie2 *table = anyCaseTrie;
+ if (uregex_start(parseRegexp, 7, &status) >= 0) {
+ table = lowerCaseTrie;
+ }
+
+ // Build the set of scripts containing confusable characters for
+ // the code point(s) specified in this input line.
+ // Sanity check that the script of the source code point is the same
+ // as the source script indicated in the input file. Failure of this check is
+ // an error in the input file.
+ // Include the source script in the set (needed for Mixed Script Confusable detection).
+ //
+ UChar32 cp;
+ for (cp=startCodePoint; cp<=endCodePoint; cp++) {
+ int32_t setIndex = utrie2_get32(table, cp);
+ BuilderScriptSet *bsset = NULL;
+ if (setIndex > 0) {
+ U_ASSERT(setIndex < scriptSets->size());
+ bsset = static_cast<BuilderScriptSet *>(scriptSets->elementAt(setIndex));
+ } else {
+ bsset = new BuilderScriptSet();
+ if (bsset == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ bsset->codePoint = cp;
+ bsset->trie = table;
+ bsset->sset = new ScriptSet();
+ setIndex = scriptSets->size();
+ bsset->index = setIndex;
+ bsset->rindex = 0;
+ if (bsset->sset == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ scriptSets->addElement(bsset, status);
+ utrie2_set32(table, cp, setIndex, &status);
+ }
+ bsset->sset->Union(targScript);
+ bsset->sset->Union(srcScript);
+
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ UScriptCode cpScript = uscript_getScript(cp, &status);
+ if (cpScript != srcScript) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto cleanup;
+ }
+ }
+ }
+
+ // Eliminate duplicate script sets. At this point we have a separate
+ // script set for every code point that had data in the input file.
+ //
+ // We eliminate underlying ScriptSet objects, not the BuildScriptSets that wrap them
+ //
+ // printf("Number of scriptSets: %d\n", scriptSets->size());
+ {
+ int32_t duplicateCount = 0;
+ rtScriptSetsCount = 2;
+ for (int32_t outeri=2; outeri<scriptSets->size(); outeri++) {
+ BuilderScriptSet *outerSet = static_cast<BuilderScriptSet *>(scriptSets->elementAt(outeri));
+ if (outerSet->index != static_cast<uint32_t>(outeri)) {
+ // This set was already identified as a duplicate.
+ // It will not be allocated a position in the runtime array of ScriptSets.
+ continue;
+ }
+ outerSet->rindex = rtScriptSetsCount++;
+ for (int32_t inneri=outeri+1; inneri<scriptSets->size(); inneri++) {
+ BuilderScriptSet *innerSet = static_cast<BuilderScriptSet *>(scriptSets->elementAt(inneri));
+ if (*(outerSet->sset) == *(innerSet->sset) && outerSet->sset != innerSet->sset) {
+ delete innerSet->sset;
+ innerSet->scriptSetOwned = FALSE;
+ innerSet->sset = outerSet->sset;
+ innerSet->index = outeri;
+ innerSet->rindex = outerSet->rindex;
+ duplicateCount++;
+ }
+ // But this doesn't get all. We need to fix the TRIE.
+ }
+ }
+ // printf("Number of distinct script sets: %d\n", rtScriptSetsCount);
+ }
+
+
+
+ // Update the Trie values to be reflect the run time script indexes (after duplicate merging).
+ // (Trie Values 0 and 1 are reserved, and the corresponding slots in scriptSets
+ // are unused, which is why the loop index starts at 2.)
+ {
+ for (int32_t i=2; i<scriptSets->size(); i++) {
+ BuilderScriptSet *bSet = static_cast<BuilderScriptSet *>(scriptSets->elementAt(i));
+ if (bSet->rindex != (uint32_t)i) {
+ utrie2_set32(bSet->trie, bSet->codePoint, bSet->rindex, &status);
+ }
+ }
+ }
+
+ // For code points with script==Common or script==Inherited,
+ // Set the reserved value of 1 into both Tries. These characters do not participate
+ // in Whole Script Confusable detection; this reserved value is the means
+ // by which they are detected.
+ {
+ UnicodeSet ignoreSet;
+ ignoreSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status);
+ UnicodeSet inheritedSet;
+ inheritedSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status);
+ ignoreSet.addAll(inheritedSet);
+ for (int32_t rn=0; rn<ignoreSet.getRangeCount(); rn++) {
+ UChar32 rangeStart = ignoreSet.getRangeStart(rn);
+ UChar32 rangeEnd = ignoreSet.getRangeEnd(rn);
+ utrie2_setRange32(anyCaseTrie, rangeStart, rangeEnd, 1, TRUE, &status);
+ utrie2_setRange32(lowerCaseTrie, rangeStart, rangeEnd, 1, TRUE, &status);
+ }
+ }
+
+ // Serialize the data to the Spoof Detector
+ {
+ utrie2_freeze(anyCaseTrie, UTRIE2_16_VALUE_BITS, &status);
+ int32_t size = utrie2_serialize(anyCaseTrie, NULL, 0, &status);
+ // printf("Any case Trie size: %d\n", size);
+ if (status != U_BUFFER_OVERFLOW_ERROR) {
+ goto cleanup;
+ }
+ status = U_ZERO_ERROR;
+ spImpl->fSpoofData->fRawData->fAnyCaseTrie = spImpl->fSpoofData->fMemLimit;
+ spImpl->fSpoofData->fRawData->fAnyCaseTrieLength = size;
+ spImpl->fSpoofData->fAnyCaseTrie = anyCaseTrie;
+ void *where = spImpl->fSpoofData->reserveSpace(size, status);
+ utrie2_serialize(anyCaseTrie, where, size, &status);
+
+ utrie2_freeze(lowerCaseTrie, UTRIE2_16_VALUE_BITS, &status);
+ size = utrie2_serialize(lowerCaseTrie, NULL, 0, &status);
+ // printf("Lower case Trie size: %d\n", size);
+ if (status != U_BUFFER_OVERFLOW_ERROR) {
+ goto cleanup;
+ }
+ status = U_ZERO_ERROR;
+ spImpl->fSpoofData->fRawData->fLowerCaseTrie = spImpl->fSpoofData->fMemLimit;
+ spImpl->fSpoofData->fRawData->fLowerCaseTrieLength = size;
+ spImpl->fSpoofData->fLowerCaseTrie = lowerCaseTrie;
+ where = spImpl->fSpoofData->reserveSpace(size, status);
+ utrie2_serialize(lowerCaseTrie, where, size, &status);
+
+ spImpl->fSpoofData->fRawData->fScriptSets = spImpl->fSpoofData->fMemLimit;
+ spImpl->fSpoofData->fRawData->fScriptSetsLength = rtScriptSetsCount;
+ ScriptSet *rtScriptSets = static_cast<ScriptSet *>
+ (spImpl->fSpoofData->reserveSpace(rtScriptSetsCount * sizeof(ScriptSet), status));
+ uint32_t rindex = 2;
+ for (int32_t i=2; i<scriptSets->size(); i++) {
+ BuilderScriptSet *bSet = static_cast<BuilderScriptSet *>(scriptSets->elementAt(i));
+ if (bSet->rindex < rindex) {
+ // We have already copied this script set to the serialized data.
+ continue;
+ }
+ U_ASSERT(rindex == bSet->rindex);
+ rtScriptSets[rindex] = *bSet->sset; // Assignment of a ScriptSet just copies the bits.
+ rindex++;
+ }
+ }
+
+ // Open new utrie2s from the serialized data. We don't want to keep the ones
+ // we just built because we would then have two copies of the data, one internal to
+ // the utries that we have already constructed, and one in the serialized data area.
+ // An alternative would be to not pre-serialize the Trie data, but that makes the
+ // spoof detector data different, depending on how the detector was constructed.
+ // It's simpler to keep the data always the same.
+
+ spImpl->fSpoofData->fAnyCaseTrie = utrie2_openFromSerialized(
+ UTRIE2_16_VALUE_BITS,
+ (const char *)spImpl->fSpoofData->fRawData + spImpl->fSpoofData->fRawData->fAnyCaseTrie,
+ spImpl->fSpoofData->fRawData->fAnyCaseTrieLength,
+ NULL,
+ &status);
+
+ spImpl->fSpoofData->fLowerCaseTrie = utrie2_openFromSerialized(
+ UTRIE2_16_VALUE_BITS,
+ (const char *)spImpl->fSpoofData->fRawData + spImpl->fSpoofData->fRawData->fLowerCaseTrie,
+ spImpl->fSpoofData->fRawData->fAnyCaseTrieLength,
+ NULL,
+ &status);
+
+
+
+cleanup:
+ if (U_FAILURE(status)) {
+ pe->line = lineNum;
+ }
+ uregex_close(parseRegexp);
+ uprv_free(input);
+
+ int32_t i;
+ for (i=0; i<scriptSets->size(); i++) {
+ BuilderScriptSet *bsset = static_cast<BuilderScriptSet *>(scriptSets->elementAt(i));
+ delete bsset;
+ }
+ delete scriptSets;
+ utrie2_close(anyCaseTrie);
+ utrie2_close(lowerCaseTrie);
+ return;
+}
+
+
+
+
+
+BuilderScriptSet::BuilderScriptSet() {
+ codePoint = -1;
+ trie = NULL;
+ sset = NULL;
+ index = 0;
+ rindex = 0;
+ scriptSetOwned = TRUE;
+}
+
+BuilderScriptSet::~BuilderScriptSet() {
+ if (scriptSetOwned) {
+ delete sset;
+ }
+}
+
+#endif
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.h b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.h
new file mode 100644
index 00000000000..2b633152368
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/uspoof_wsconf.h
@@ -0,0 +1,70 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2009, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+* file name: uspoof_buildwsconf.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2009Jan19
+* created by: Andy Heninger
+*
+* Internal classes and functions
+* for compiling whole script confusable data into its binary (runtime) form.
+*/
+
+#ifndef __USPOOF_BUILDWSCONF_H__
+#define __USPOOF_BUILDWSCONF_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "uspoof_impl.h"
+#include "utrie2.h"
+
+
+U_NAMESPACE_BEGIN
+
+//
+// class BuilderScriptSet. Represents the set of scripts (Script Codes)
+// containing characters that are confusable with one specific
+// code point.
+//
+
+class BuilderScriptSet: public UMemory {
+ public:
+ UChar32 codePoint; // The source code point.
+ UTrie2 *trie; // Any-case or Lower-case Trie.
+ // These Trie tables are the final result of the
+ // build. This flag indicates which of the two
+ // this set of data is for.
+ ScriptSet *sset; // The set of scripts itself.
+
+ // Vectors of all B
+ uint32_t index; // Index of this set in the Build Time vector
+ // of script sets.
+ uint32_t rindex; // Index of this set in the final (runtime)
+ // array of sets.
+ UBool scriptSetOwned; // True if this BuilderScriptSet owns (should delete)
+ // its underlying sset.
+
+ BuilderScriptSet();
+ ~BuilderScriptSet();
+};
+
+U_NAMESPACE_END
+
+void buildWSConfusableData(SpoofImpl *spImpl, const char * confusablesWS,
+ int32_t confusablesWSLen, UParseError *pe, UErrorCode &status);
+
+
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif // !UCONFIG_NO_NORMALIZATION
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/usrchimp.h b/Build/source/libs/icu/icu-4.8.1/i18n/usrchimp.h
new file mode 100644
index 00000000000..986db33699f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/usrchimp.h
@@ -0,0 +1,140 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2010 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/normalizer2.h"
+#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;
+ int16_t elementComparisonType;
+ 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't 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_];
+ int32_t PCELength;
+ int64_t *PCE;
+ int64_t PCEBuffer[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;
+ const U_NAMESPACE_QUALIFIER Normalizer2 *nfd;
+ // 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-4.8.1/i18n/utmscale.c b/Build/source/libs/icu/icu-4.8.1/i18n/utmscale.c
new file mode 100644
index 00000000000..33f5d9212d0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/utrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/utrans.cpp
new file mode 100644
index 00000000000..16a09bdcb6a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/utrans.cpp
@@ -0,0 +1,495 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2009, 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
+
+ Transliterator *trans = NULL;
+ trans = Transliterator::createFromRules(ID, ruleStr, dir, *parseError, *status);
+ if(U_FAILURE(*status)) {
+ return 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-4.8.1/i18n/vtzone.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/vtzone.cpp
new file mode 100644
index 00000000000..51a6a81ef46
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/vtzone.cpp
@@ -0,0 +1,2625 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include <typeinfo> // for 'typeid' to work
+
+#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
+
+// This is the deleter that will be use to remove TimeZoneRule
+U_CDECL_BEGIN
+static void U_CALLCONV
+deleteTimeZoneRule(void* obj) {
+ delete (TimeZoneRule*) obj;
+}
+U_CDECL_END
+
+// 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& zonename) {
+ zonename = tzid;
+ if (isDST) {
+ zonename += UNICODE_STRING_SIMPLE("(DST)");
+ } else {
+ zonename += 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& zonename, 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(zonename, 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& zonename, 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(zonename, 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(zonename, 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 (typeid(*this) != typeid(that) || !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 = 0;
+ bundle = ures_openDirect(NULL, "zoneinfo64", &status);
+ versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
+ if (U_SUCCESS(status)) {
+ vtz->icutzver.setTo(versionStr, len);
+ }
+ ures_close(bundle);
+ return vtz;
+}
+
+VTimeZone*
+VTimeZone::createVTimeZoneFromBasicTimeZone(const BasicTimeZone& basic_time_zone, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ VTimeZone *vtz = new VTimeZone();
+ if (vtz == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ vtz->tz = (BasicTimeZone *)basic_time_zone.clone();
+ if (vtz->tz == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete vtz;
+ return NULL;
+ }
+ vtz->tz->getID(vtz->olsonzid);
+
+ // Set ICU tzdata version
+ UResourceBundle *bundle = NULL;
+ const UChar* versionStr = NULL;
+ int32_t len = 0;
+ bundle = ures_openDirect(NULL, "zoneinfo64", &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 zonename; // 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
+
+ int32_t finalRuleIdx = -1;
+ int32_t finalRuleCount = 0;
+
+ rules = new UVector(status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ // Set the deleter to remove TimeZoneRule vectors to avoid memory leaks due to unowned TimeZoneRules.
+ rules->setDeleter(deleteTimeZoneRule);
+
+ dates = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ if (rules == NULL || dates == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ 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();
+ zonename.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) {
+ zonename = 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 zonename is not available, create one from tzid
+ if (zonename.length() == 0) {
+ getDefaultTZName(tzid, dst, zonename);
+ }
+
+ // 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(zonename, rawOffset, dstSavings, start, dates, fromOffset, status);
+ } else {
+ rule = createRuleByRDATE(zonename, 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, zonename);
+ initialRule = new InitialTimeZoneRule(zonename,
+ initialRawOffset, initialDSTSavings);
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanupParse;
+ }
+
+ // Finally, create the RuleBasedTimeZone
+ rbtz = new RuleBasedTimeZone(tzid, initialRule);
+ if (rbtz == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanupParse;
+ }
+ initialRule = NULL; // already adopted by RBTZ, no need to delete
+
+ for (n = 0; n < rules->size(); n++) {
+ TimeZoneRule *r = (TimeZoneRule*)rules->elementAt(n);
+ AnnualTimeZoneRule *atzrule = dynamic_cast<AnnualTimeZoneRule *>(r);
+ if (atzrule != NULL) {
+ if (atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+ finalRuleCount++;
+ finalRuleIdx = n;
+ }
+ }
+ }
+ if (finalRuleCount > 2) {
+ // Too many final rules
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ goto cleanupParse;
+ }
+
+ if (finalRuleCount == 1) {
+ if (rules->size() == 1) {
+ // Only one final rule, only governs the initial rule,
+ // which is already initialized, thus, we do not need to
+ // add this transition rule
+ rules->removeAllElements();
+ } else {
+ // Normalize the final rule
+ AnnualTimeZoneRule *finalRule = (AnnualTimeZoneRule*)rules->elementAt(finalRuleIdx);
+ int32_t tmpRaw = finalRule->getRawOffset();
+ int32_t tmpDST = finalRule->getDSTSavings();
+
+ // Find the last non-final rule
+ UDate finalStart, start;
+ finalRule->getFirstStart(initialRawOffset, initialDSTSavings, finalStart);
+ start = finalStart;
+ for (n = 0; n < rules->size(); n++) {
+ if (finalRuleIdx == n) {
+ continue;
+ }
+ TimeZoneRule *r = (TimeZoneRule*)rules->elementAt(n);
+ UDate lastStart;
+ r->getFinalStart(tmpRaw, tmpDST, lastStart);
+ if (lastStart > start) {
+ finalRule->getNextStart(lastStart,
+ r->getRawOffset(),
+ r->getDSTSavings(),
+ FALSE,
+ start);
+ }
+ }
+
+ TimeZoneRule *newRule;
+ UnicodeString tznam;
+ if (start == finalStart) {
+ // Transform this into a single transition
+ newRule = new TimeArrayTimeZoneRule(
+ finalRule->getName(tznam),
+ finalRule->getRawOffset(),
+ finalRule->getDSTSavings(),
+ &finalStart,
+ 1,
+ DateTimeRule::UTC_TIME);
+ } else {
+ // Update the end year
+ int32_t y, m, d, dow, doy, mid;
+ Grego::timeToFields(start, y, m, d, dow, doy, mid);
+ newRule = new AnnualTimeZoneRule(
+ finalRule->getName(tznam),
+ finalRule->getRawOffset(),
+ finalRule->getDSTSavings(),
+ *(finalRule->getRule()),
+ finalRule->getStartYear(),
+ y);
+ }
+ if (newRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanupParse;
+ }
+ rules->removeElementAt(finalRuleIdx);
+ rules->addElement(newRule, status);
+ if (U_FAILURE(status)) {
+ delete newRule;
+ goto cleanupParse;
+ }
+ }
+ }
+
+ 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;
+ const AnnualTimeZoneRule *atzrule;
+ if (isDst) {
+ if (finalDstRule == NULL
+ && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != NULL
+ && atzrule->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
+ && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != NULL
+ && atzrule->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& zonename,
+ int32_t fromOffset, int32_t toOffset, UDate time, UBool withRDATE,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ beginZoneProps(writer, isDst, zonename, 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& zonename,
+ 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, zonename, 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& zonename,
+ 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, zonename, 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& zonename,
+ 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, zonename, 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, zonename, 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, zonename, 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& zonename,
+ 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, zonename, 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, zonename, 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, zonename, fromOffset, toOffset,
+ UCAL_FEBRUARY, -1, dayOfWeek, startTime, untilTime, status);
+ } else {
+ // Otherwise, convert this to DOW_GEQ_DOM rule
+ writeZonePropsByDOW_GEQ_DOM(writer, isDst, zonename, 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();
+ }
+
+ // If the rule's mills in a day is out of range, adjust start time.
+ // Olson tzdata supports 24:00 of a day, but VTIMEZONE does not.
+ // See ticket#7008/#7518
+
+ int32_t timeInDay = dtrule->getRuleMillisInDay();
+ if (timeInDay < 0) {
+ startTime = startTime + (0 - timeInDay);
+ } else if (timeInDay >= U_MILLIS_PER_DAY) {
+ startTime = startTime - (timeInDay - (U_MILLIS_PER_DAY - 1));
+ }
+
+ 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& zonename,
+ 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(zonename);
+ 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-4.8.1/i18n/vzone.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/vzone.cpp
new file mode 100644
index 00000000000..3aa2dbbebcc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/vzone.cpp
@@ -0,0 +1,185 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C API: VTimeZone classes
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "vzone.h"
+#include "unicode/vtzone.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/parsepos.h"
+
+U_NAMESPACE_USE
+
+U_CAPI VZone* U_EXPORT2
+vzone_openID(const UChar* ID, int32_t idLength){
+ UnicodeString s(idLength==-1, ID, idLength);
+ return (VZone*) (VTimeZone::createVTimeZoneByID(s));
+}
+
+U_CAPI VZone* U_EXPORT2
+vzone_openData(const UChar* vtzdata, int32_t vtzdataLength, UErrorCode& status) {
+ UnicodeString s(vtzdataLength==-1, vtzdata, vtzdataLength);
+ return (VZone*) (VTimeZone::createVTimeZone(s,status));
+}
+
+U_CAPI void U_EXPORT2
+vzone_close(VZone* zone) {
+ delete (VTimeZone*)zone;
+}
+
+U_CAPI VZone* U_EXPORT2
+vzone_clone(const VZone *zone) {
+ return (VZone*) (((VTimeZone*)zone)->VTimeZone::clone());
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_equals(const VZone* zone1, const VZone* zone2) {
+ return *(const VTimeZone*)zone1 == *(const VTimeZone*)zone2;
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_getTZURL(VZone* zone, UChar* & url, int32_t & urlLength) {
+ UnicodeString s;
+ UBool b = ((VTimeZone*)zone)->VTimeZone::getTZURL(s);
+
+ urlLength = s.length();
+ memcpy(url,s.getBuffer(),urlLength);
+
+ return b;
+}
+
+U_CAPI void U_EXPORT2
+vzone_setTZURL(VZone* zone, UChar* url, int32_t urlLength) {
+ UnicodeString s(urlLength==-1, url, urlLength);
+ return ((VTimeZone*)zone)->VTimeZone::setTZURL(url);
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_getLastModified(VZone* zone, UDate& lastModified) {
+ return ((VTimeZone*)zone)->VTimeZone::getLastModified(lastModified);
+}
+
+U_CAPI void U_EXPORT2
+vzone_setLastModified(VZone* zone, UDate lastModified) {
+ return ((VTimeZone*)zone)->VTimeZone::setLastModified(lastModified);
+}
+
+U_CAPI void U_EXPORT2
+vzone_write(VZone* zone, UChar* & result, int32_t & resultLength, UErrorCode& status) {
+ UnicodeString s;
+ ((VTimeZone*)zone)->VTimeZone::write(s, status);
+
+ resultLength = s.length();
+ result = (UChar*)uprv_malloc(resultLength);
+ memcpy(result,s.getBuffer(),resultLength);
+
+ return;
+}
+
+U_CAPI void U_EXPORT2
+vzone_writeFromStart(VZone* zone, UDate start, UChar* & result, int32_t & resultLength, UErrorCode& status) {
+ UnicodeString s;
+ ((VTimeZone*)zone)->VTimeZone::write(start, s, status);
+
+ resultLength = s.length();
+ result = (UChar*)uprv_malloc(resultLength);
+ memcpy(result,s.getBuffer(),resultLength);
+
+ return;
+}
+
+U_CAPI void U_EXPORT2
+vzone_writeSimple(VZone* zone, UDate time, UChar* & result, int32_t & resultLength, UErrorCode& status) {
+ UnicodeString s;
+ ((VTimeZone*)zone)->VTimeZone::writeSimple(time, s, status);
+
+ resultLength = s.length();
+ result = (UChar*)uprv_malloc(resultLength);
+ memcpy(result,s.getBuffer(),resultLength);
+
+ return;
+}
+
+U_CAPI int32_t U_EXPORT2
+vzone_getOffset(VZone* zone, uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) {
+ return ((VTimeZone*)zone)->VTimeZone::getOffset(era, year, month, day, dayOfWeek, millis, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+vzone_getOffset2(VZone* zone, uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t monthLength, UErrorCode& status) {
+ return ((VTimeZone*)zone)->VTimeZone::getOffset(era, year, month, day, dayOfWeek, millis, monthLength, status);
+}
+
+U_CAPI void U_EXPORT2
+vzone_getOffset3(VZone* zone, UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) {
+ return ((VTimeZone*)zone)->VTimeZone::getOffset(date, local, rawOffset, dstOffset, ec);
+}
+
+U_CAPI void U_EXPORT2
+vzone_setRawOffset(VZone* zone, int32_t offsetMillis) {
+ return ((VTimeZone*)zone)->VTimeZone::setRawOffset(offsetMillis);
+}
+
+U_CAPI int32_t U_EXPORT2
+vzone_getRawOffset(VZone* zone) {
+ return ((VTimeZone*)zone)->VTimeZone::getRawOffset();
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_useDaylightTime(VZone* zone) {
+ return ((VTimeZone*)zone)->VTimeZone::useDaylightTime();
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_inDaylightTime(VZone* zone, UDate date, UErrorCode& status) {
+ return ((VTimeZone*)zone)->VTimeZone::inDaylightTime(date, status);
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_hasSameRules(VZone* zone, const VZone* other) {
+ return ((VTimeZone*)zone)->VTimeZone::hasSameRules(*(VTimeZone*)other);
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_getNextTransition(VZone* zone, UDate base, UBool inclusive, ZTrans* result) {
+ return ((VTimeZone*)zone)->VTimeZone::getNextTransition(base, inclusive, *(TimeZoneTransition*)result);
+}
+
+U_CAPI UBool U_EXPORT2
+vzone_getPreviousTransition(VZone* zone, UDate base, UBool inclusive, ZTrans* result) {
+ return ((VTimeZone*)zone)->VTimeZone::getPreviousTransition(base, inclusive, *(TimeZoneTransition*)result);
+}
+
+U_CAPI int32_t U_EXPORT2
+vzone_countTransitionRules(VZone* zone, UErrorCode& status) {
+ return ((VTimeZone*)zone)->VTimeZone::countTransitionRules(status);
+}
+
+U_CAPI UClassID U_EXPORT2
+vzone_getStaticClassID(VZone* zone) {
+ return ((VTimeZone*)zone)->VTimeZone::getStaticClassID();
+}
+
+U_CAPI UClassID U_EXPORT2
+vzone_getDynamicClassID(VZone* zone) {
+ return ((VTimeZone*)zone)->VTimeZone::getDynamicClassID();
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/vzone.h b/Build/source/libs/icu/icu-4.8.1/i18n/vzone.h
new file mode 100644
index 00000000000..5752be4f3cd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/vzone.h
@@ -0,0 +1,360 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+/**
+* \file
+* \brief C API: RFC2445 VTIMEZONE support
+*
+* <p>This is a C wrapper around the C++ VTimeZone class.</p>
+*/
+
+#ifndef __VZONE_H
+#define __VZONE_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "ztrans.h"
+
+#ifndef UCNV_H
+struct VZone;
+/**
+ * A UnicodeSet. Use the vzone_* API to manipulate. Create with
+ * vzone_open*, and destroy with vzone_close.
+ */
+typedef struct VZone VZone;
+#endif
+
+/*********************************************************************
+ * VZone API
+ *********************************************************************/
+
+/**
+ * Creates a vzone from the given time zone ID.
+ * @param ID The time zone ID, such as America/New_York
+ * @param idLength, length of the ID parameter
+ * @return A vzone object initialized by the time zone ID,
+ * or NULL when the ID is unknown.
+ */
+U_CAPI VZone* U_EXPORT2
+vzone_openID(const UChar* ID, int32_t idLength);
+
+/**
+ * Create a vzone instance by RFC2445 VTIMEZONE data
+ * @param vtzdata The string including VTIMEZONE data block
+ * @param vtzdataLength, length of the vtzdata
+ * @param status Output param to filled in with a success or an error.
+ * @return A vzone initialized by the VTIMEZONE data or
+ * NULL if failed to load the rule from the VTIMEZONE data.
+ */
+U_CAPI VZone* U_EXPORT2
+vzone_openData(const UChar* vtzdata, int32_t vtzdataLength, UErrorCode& status);
+
+/**
+ * Disposes of the storage used by a VZone object. This function should
+ * be called exactly once for objects returned by vzone_open*.
+ * @param set the object to dispose of
+ */
+U_CAPI void U_EXPORT2
+vzone_close(VZone* zone);
+
+/**
+ * Returns a copy of this object.
+ * @param zone the original vzone
+ * @return the newly allocated copy of the vzone
+ */
+U_CAPI VZone* U_EXPORT2
+vzone_clone(const VZone *zone);
+
+/**
+ * Returns true if zone1 is identical to zone2
+ * and vis versa.
+ * @param zone1 to be checked for containment
+ * @param zone2 to be checked for containment
+ * @return true if the test condition is met
+ */
+U_CAPI UBool U_EXPORT2
+vzone_equals(const VZone* zone1, const VZone* zone2);
+
+/**
+ * Gets the RFC2445 TZURL property value. When a vzone 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 zone, the vzone to use
+ * @param url Receives the RFC2445 TZURL property value.
+ * @param urlLength, length of the url
+ * @return TRUE if TZURL attribute is available and value is set.
+ */
+U_CAPI UBool U_EXPORT2
+vzone_getTZURL(VZone* zone, UChar* & url, int32_t & urlLength);
+
+/**
+ * Sets the RFC2445 TZURL property value.
+ * @param zone, the vzone to use
+ * @param url The TZURL property value.
+ * @param urlLength, length of the url
+ */
+U_CAPI void U_EXPORT2
+vzone_setTZURL(VZone* zone, UChar* url, int32_t urlLength);
+
+/**
+ * Gets the RFC2445 LAST-MODIFIED property value. When a vzone 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 zone, the vzone to use
+ * @param lastModified Receives the last modified date.
+ * @return TRUE if lastModified attribute is available and value is set.
+ */
+U_CAPI UBool U_EXPORT2
+vzone_getLastModified(VZone* zone, UDate& lastModified);
+
+/**
+ * Sets the RFC2445 LAST-MODIFIED property value.
+ * @param zone, the vzone to use
+ * @param lastModified The LAST-MODIFIED date.
+ */
+U_CAPI void U_EXPORT2
+vzone_setLastModified(VZone* zone, UDate lastModified);
+
+/**
+ * Writes RFC2445 VTIMEZONE data for this time zone
+ * @param zone, the vzone to use
+ * @param result Output param to filled in with the VTIMEZONE data.
+ * @param resultLength, length of the result output
+ * @param status Output param to filled in with a success or an error.
+ */
+U_CAPI void U_EXPORT2
+vzone_write(VZone* zone, UChar* & result, int32_t & resultLength, UErrorCode& status);
+
+/**
+ * Writes RFC2445 VTIMEZONE data for this time zone applicalbe
+ * for dates after the specified start time.
+ * @param zone, the vzone to use
+ * @param start The start date.
+ * @param result Output param to filled in with the VTIMEZONE data.
+ * @param resultLength, length of the result output
+ * @param status Output param to filled in with a success or an error.
+ */
+U_CAPI void U_EXPORT2
+vzone_writeFromStart(VZone* zone, UDate start, UChar* & result, int32_t & resultLength, UErrorCode& status);
+
+/**
+ * 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 zone, the vzone to use
+ * @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.
+ */
+U_CAPI void U_EXPORT2
+vzone_writeSimple(VZone* zone, UDate time, UChar* & result, int32_t & resultLength, 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 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 zone, the vzone to use
+ * @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.
+ */
+U_CAPI int32_t U_EXPORT2
+vzone_getOffset(VZone* zone, uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status);
+
+/**
+ * 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 zone, the vzone to use
+ * @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.
+ */
+U_CAPI int32_t U_EXPORT2
+vzone_getOffset2(VZone* zone, uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t monthLength, UErrorCode& status);
+
+/**
+ * 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 zone, the vzone to use
+ * @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
+ */
+U_CAPI void U_EXPORT2
+vzone_getOffset3(VZone* zone, UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec);
+
+/**
+ * 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 zone, the vzone to use
+ * @param offsetMillis The new raw GMT offset for this time zone.
+ */
+U_CAPI void U_EXPORT2
+vzone_setRawOffset(VZone* zone, 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).
+ *
+ * @param zone, the vzone to use
+ * @return The TimeZone's raw GMT offset.
+ */
+U_CAPI int32_t U_EXPORT2
+vzone_getRawOffset(VZone* zone);
+
+/**
+ * Queries if this time zone uses daylight savings time.
+ * @param zone, the vzone to use
+ * @return true if this time zone uses daylight savings time,
+ * false, otherwise.
+ */
+U_CAPI UBool U_EXPORT2
+vzone_useDaylightTime(VZone* zone);
+
+/**
+ * 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 zone, the vzone to use
+ * @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.
+ */
+U_INTERNAL UBool U_EXPORT2
+vzone_inDaylightTime(VZone* zone, UDate date, UErrorCode& status);
+
+/**
+ * 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 zone, the vzone to use
+ * @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
+ */
+U_CAPI UBool U_EXPORT2
+vzone_hasSameRules(VZone* zone, const VZone* other);
+
+/**
+ * Gets the first time zone transition after the base time.
+ * @param zone, the vzone to use
+ * @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.
+ */
+U_CAPI UBool U_EXPORT2
+vzone_getNextTransition(VZone* zone, UDate base, UBool inclusive, ZTrans* result);
+
+/**
+ * Gets the most recent time zone transition before the base time.
+ * @param zone, the vzone to use
+ * @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.
+ */
+U_CAPI UBool U_EXPORT2
+vzone_getPreviousTransition(VZone* zone, UDate base, UBool inclusive, ZTrans* result);
+
+/**
+ * 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 zone, the vzone to use
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ */
+U_CAPI int32_t U_EXPORT2
+vzone_countTransitionRules(VZone* zone, UErrorCode& status);
+
+/**
+ * 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>
+ * @param zone, the vzone to use
+ * @return The class ID for all objects of this class.
+ */
+U_CAPI UClassID U_EXPORT2
+vzone_getStaticClassID(VZone* zone);
+
+/**
+ * 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.
+ *
+ * @param zone, the vzone to use
+ * @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.
+ */
+U_CAPI UClassID U_EXPORT2
+vzone_getDynamicClassID(VZone* zone);
+
+#endif // __VZONE_H
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.cpp
new file mode 100644
index 00000000000..8fedabd6753
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.cpp
@@ -0,0 +1,321 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2009, 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 "wintzimpl.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* Win32DateFormat::getTimeDateFormat(const Calendar *cal, const Locale *locale, UErrorCode &status) const
+{
+ 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;
+ int32_t glueIndex = DateFormat::kDateTime;
+ int32_t patSize = ures_getSize(patBundle);
+ if (patSize >= (DateFormat::kDateTimeOffset + DateFormat::kShort + 1)) {
+ // Get proper date time format
+ glueIndex = (int32_t)(DateFormat::kDateTimeOffset + (fDateStyle - DateFormat::kDateOffset));
+ }
+ const UChar *resStr = ures_getStringByIndex(patBundle, glueIndex, &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-4.8.1/i18n/windtfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.h
new file mode 100644
index 00000000000..aea8f0a4458
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/windtfmt.h
@@ -0,0 +1,140 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2011, 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ virtual void adoptTimeZone(TimeZone* zoneToAdopt);
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object.
+ * @param zone the new time zone.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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* getTimeDateFormat(const Calendar *cal, const Locale *locale, UErrorCode &status) 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-4.8.1/i18n/winnmfmt.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/winnmfmt.cpp
new file mode 100644
index 00000000000..4207c52e7e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/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-4.8.1/i18n/winnmfmt.h b/Build/source/libs/icu/icu-4.8.1/i18n/winnmfmt.h
new file mode 100644
index 00000000000..7b2f9ac8548
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/winnmfmt.h
@@ -0,0 +1,161 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2011, 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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
+ */
+ 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
+ */
+ 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.
+ */
+ 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.
+ */
+ 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-4.8.1/i18n/wintzimpl.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.cpp
new file mode 100644
index 00000000000..fb7de50a812
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.cpp
@@ -0,0 +1,157 @@
+/*
+********************************************************************************
+* Copyright (C) 2009, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINTZIMPL.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#include "wintzimpl.h"
+
+#include "unicode/unistr.h"
+#include "unicode/timezone.h"
+#include "unicode/basictz.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include "cmemory.h"
+
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+
+#include <windows.h>
+
+U_NAMESPACE_USE
+
+static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SYSTEMTIME &standardDate, int32_t &bias, int32_t &daylightBias, int32_t &standardBias) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool result = TRUE;
+ BasicTimeZone *btz = (BasicTimeZone*)tz; // we should check type
+ InitialTimeZoneRule *initial = NULL;
+ AnnualTimeZoneRule *std = NULL, *dst = NULL;
+
+ btz->getSimpleRulesNear(uprv_getUTCtime(), initial, std, dst, status);
+ if (U_SUCCESS(status)) {
+ if (std == NULL || dst == NULL) {
+ bias = -1 * (initial->getRawOffset()/60000);
+ standardBias = 0;
+ daylightBias = 0;
+ // Do not use DST. Set 0 to all stadardDate/daylightDate fields
+ standardDate.wYear = standardDate.wMonth = standardDate.wDayOfWeek = standardDate.wDay =
+ standardDate.wHour = standardDate.wMinute = standardDate.wSecond = standardDate.wMilliseconds = 0;
+ daylightDate.wYear = daylightDate.wMonth = daylightDate.wDayOfWeek = daylightDate.wDay =
+ daylightDate.wHour = daylightDate.wMinute = daylightDate.wSecond = daylightDate.wMilliseconds = 0;
+ } else {
+ U_ASSERT(std->getRule()->getDateRuleType() == DateTimeRule::DOW);
+ U_ASSERT(dst->getRule()->getDateRuleType() == DateTimeRule::DOW);
+
+ bias = -1 * (std->getRawOffset()/60000);
+ standardBias = 0;
+ daylightBias = -1 * (dst->getDSTSavings()/60000);
+ // Always use DOW type rule
+ int32_t hour, min, sec, mil;
+ standardDate.wYear = 0;
+ standardDate.wMonth = std->getRule()->getRuleMonth() + 1;
+ standardDate.wDay = std->getRule()->getRuleWeekInMonth();
+ if (standardDate.wDay < 0) {
+ standardDate.wDay = 5;
+ }
+ standardDate.wDayOfWeek = std->getRule()->getRuleDayOfWeek() - 1;
+
+ mil = std->getRule()->getRuleMillisInDay();
+ hour = mil/3600000;
+ mil %= 3600000;
+ min = mil/60000;
+ mil %= 60000;
+ sec = mil/1000;
+ mil %= 1000;
+
+ standardDate.wHour = hour;
+ standardDate.wMinute = min;
+ standardDate.wSecond = sec;
+ standardDate.wMilliseconds = mil;
+
+ daylightDate.wYear = 0;
+ daylightDate.wMonth = dst->getRule()->getRuleMonth() + 1;
+ daylightDate.wDay = dst->getRule()->getRuleWeekInMonth();
+ if (daylightDate.wDay < 0) {
+ daylightDate.wDay = 5;
+ }
+ daylightDate.wDayOfWeek = dst->getRule()->getRuleDayOfWeek() - 1;
+
+ mil = dst->getRule()->getRuleMillisInDay();
+ hour = mil/3600000;
+ mil %= 3600000;
+ min = mil/60000;
+ mil %= 60000;
+ sec = mil/1000;
+ mil %= 1000;
+
+ daylightDate.wHour = hour;
+ daylightDate.wMinute = min;
+ daylightDate.wSecond = sec;
+ daylightDate.wMilliseconds = mil;
+ }
+ } else {
+ result = FALSE;
+ }
+
+ delete initial;
+ delete std;
+ delete dst;
+
+ return result;
+}
+
+static UBool getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length) {
+ UBool result = FALSE;
+ UnicodeString id = UnicodeString(icuid, length);
+ TimeZone *tz = TimeZone::createTimeZone(id);
+
+ if (tz != NULL) {
+ int32_t bias;
+ int32_t daylightBias;
+ int32_t standardBias;
+ SYSTEMTIME daylightDate;
+ SYSTEMTIME standardDate;
+
+ if (getSystemTimeInformation(tz, daylightDate, standardDate, bias, daylightBias, standardBias)) {
+ uprv_memset(zoneInfo, 0, sizeof(TIME_ZONE_INFORMATION)); // We do not set standard/daylight names, so nullify first.
+ zoneInfo->Bias = bias;
+ zoneInfo->DaylightBias = daylightBias;
+ zoneInfo->StandardBias = standardBias;
+ zoneInfo->DaylightDate = daylightDate;
+ zoneInfo->StandardDate = standardDate;
+
+ result = TRUE;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Given the timezone icuid, fill in zoneInfo by calling auxillary functions that creates a timezone and extract the
+ * information to put into zoneInfo. This includes bias and standard time date and daylight saving date.
+ */
+U_CAPI UBool U_EXPORT2
+uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length)
+{
+ if (getWindowsTimeZoneInfo(zoneInfo, icuid, length)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.h b/Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.h
new file mode 100644
index 00000000000..e7083e9226e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/wintzimpl.h
@@ -0,0 +1,37 @@
+/*
+********************************************************************************
+* Copyright (C) 2008, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINTZIMPL.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINTZIMPL
+#define __WINTZIMPL
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+/**
+ * \file
+ * \brief C API: Utilities for dealing w/ Windows time zones.
+ */
+U_CDECL_BEGIN
+/* Forward declarations for Windows types... */
+typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
+U_CDECL_END
+
+/*
+ * This method was moved over from common/wintz.h to allow for access to i18n functions
+ * needed to get the Windows time zone information without using static tables.
+ */
+U_CAPI UBool U_EXPORT2
+uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length);
+
+
+#endif /* #ifdef U_WINDOWS */
+
+#endif /* __WINTZIMPL */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.cpp
new file mode 100644
index 00000000000..01de17cf062
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.cpp
@@ -0,0 +1,844 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, 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"
+#include "uassert.h"
+#include "uresimp.h"
+#include "uhash.h"
+#include "olsontz.h"
+
+static UMTX gZoneMetaLock = NULL;
+
+// CLDR Canonical ID mapping table
+static UHashtable *gCanonicalIDCache = NULL;
+static UBool gCanonicalIDCacheInitialized = FALSE;
+
+// Metazone mapping table
+static UHashtable *gOlsonToMeta = NULL;
+static UBool gOlsonToMetaInitialized = FALSE;
+
+// Available metazone IDs vector and table
+static U_NAMESPACE_QUALIFIER UVector *gMetaZoneIDs = NULL;
+static UHashtable *gMetaZoneIDTable = NULL;
+static UBool gMetaZoneIDsInitialized = FALSE;
+
+// Country info vectors
+static U_NAMESPACE_QUALIFIER UVector *gSingleZoneCountries = NULL;
+static U_NAMESPACE_QUALIFIER UVector *gMultiZonesCountries = NULL;
+static UBool gCountryInfoVectorsInitialized = FALSE;
+
+U_CDECL_BEGIN
+
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV zoneMeta_cleanup(void)
+{
+ umtx_destroy(&gZoneMetaLock);
+
+ if (gCanonicalIDCache != NULL) {
+ uhash_close(gCanonicalIDCache);
+ gCanonicalIDCache = NULL;
+ }
+ gCanonicalIDCacheInitialized = FALSE;
+
+ if (gOlsonToMeta != NULL) {
+ uhash_close(gOlsonToMeta);
+ gOlsonToMeta = NULL;
+ }
+ gOlsonToMetaInitialized = FALSE;
+
+ if (gMetaZoneIDTable != NULL) {
+ uhash_close(gMetaZoneIDTable);
+ }
+ // delete after closing gMetaZoneIDTable, because it holds
+ // value objects held by the hashtable
+ delete gMetaZoneIDs;
+ gMetaZoneIDsInitialized = FALSE;
+
+ delete gSingleZoneCountries;
+ delete gMultiZonesCountries;
+ gCountryInfoVectorsInitialized = FALSE;
+
+ return TRUE;
+}
+
+/**
+ * Deleter for UChar* string
+ */
+static void U_CALLCONV
+deleteUCharString(void *obj) {
+ UChar *entry = (UChar*)obj;
+ uprv_free(entry);
+}
+
+/**
+ * Deleter for UVector
+ */
+static void U_CALLCONV
+deleteUVector(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER UVector*) obj;
+}
+
+/**
+ * Deleter for OlsonToMetaMappingEntry
+ */
+static void U_CALLCONV
+deleteOlsonToMetaMappingEntry(void *obj) {
+ U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry *entry = (U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry*)obj;
+ uprv_free(entry);
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+#define ZID_KEY_MAX 128
+
+static const char gMetaZones[] = "metaZones";
+static const char gMetazoneInfo[] = "metazoneInfo";
+static const char gMapTimezonesTag[] = "mapTimezones";
+
+static const char gTimeZoneTypes[] = "timezoneTypes";
+static const char gTypeAliasTag[] = "typeAlias";
+static const char gTypeMapTag[] = "typeMap";
+static const char gTimezoneTag[] = "timezone";
+
+static const char gWorldTag[] = "001";
+
+static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
+
+static const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31,
+ 0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x00}; // "1970-01-01 00:00"
+static const UChar gDefaultTo[] = {0x39, 0x39, 0x39, 0x39, 0x2D, 0x31, 0x32, 0x2D, 0x33, 0x31,
+ 0x20, 0x32, 0x33, 0x3A, 0x35, 0x39, 0x00}; // "9999-12-31 23:59"
+
+#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((int32_t)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((int32_t)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((int32_t)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((int32_t)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((int32_t)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;
+}
+
+const UChar* U_EXPORT2
+ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ int32_t len = tzid.length();
+ if (len > ZID_KEY_MAX) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ // Checking the cached results
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gCanonicalIDCacheInitialized, initialized);
+ if (!initialized) {
+ // Create empty hashtable
+ umtx_lock(&gZoneMetaLock);
+ {
+ if (!gCanonicalIDCacheInitialized) {
+ gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (gCanonicalIDCache == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ gCanonicalIDCache = NULL;
+ return NULL;
+ }
+ // No key/value deleters - keys/values are from a resource bundle
+ gCanonicalIDCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+ }
+
+ const UChar *canonicalID = NULL;
+
+ UErrorCode tmpStatus = U_ZERO_ERROR;
+ UChar utzid[ZID_KEY_MAX + 1];
+ tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus);
+ U_ASSERT(tmpStatus == U_ZERO_ERROR); // we checked the length of tzid already
+
+ // Check if it was already cached
+ umtx_lock(&gZoneMetaLock);
+ {
+ canonicalID = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ if (canonicalID != NULL) {
+ return canonicalID;
+ }
+
+ // If not, resolve CLDR canonical ID with resource data
+ UBool isInputCanonical = FALSE;
+ char id[ZID_KEY_MAX + 1];
+ const UChar* idChars = tzid.getBuffer();
+
+ u_UCharsToChars(idChars,id,len);
+ id[len] = (char) 0; // Make sure it is null terminated.
+
+ // replace '/' with ':'
+ char *p = id;
+ while (*p++) {
+ if (*p == '/') {
+ *p = ':';
+ }
+ }
+
+ UResourceBundle *top = ures_openDirect(NULL, gTimeZoneTypes, &tmpStatus);
+ UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, NULL, &tmpStatus);
+ ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
+ ures_getByKey(rb, id, rb, &tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // type entry (canonical) found
+ // the input is the canonical ID. resolve to const UChar*
+ canonicalID = TimeZone::findID(tzid);
+ isInputCanonical = TRUE;
+ }
+
+ if (canonicalID == NULL) {
+ // If a map element not found, then look for an alias
+ tmpStatus = U_ZERO_ERROR;
+ ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus);
+ ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
+ const UChar *canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // canonical map found
+ canonicalID = canonical;
+ }
+
+ if (canonicalID == NULL) {
+ // Dereference the input ID using the tz data
+ const UChar *derefer = TimeZone::dereferOlsonLink(tzid);
+ if (derefer == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ len = u_strlen(derefer);
+ u_UCharsToChars(derefer,id,len);
+ id[len] = (char) 0; // Make sure it is null terminated.
+
+ // replace '/' with ':'
+ char *p = id;
+ while (*p++) {
+ if (*p == '/') {
+ *p = ':';
+ }
+ }
+
+ // If a dereference turned something up then look for an alias.
+ // rb still points to the alias table, so we don't have to go looking
+ // for it.
+ tmpStatus = U_ZERO_ERROR;
+ canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // canonical map for the dereferenced ID found
+ canonicalID = canonical;
+ } else {
+ canonicalID = derefer;
+ isInputCanonical = TRUE;
+ }
+ }
+ }
+ }
+ ures_close(rb);
+ ures_close(top);
+
+ if (U_SUCCESS(status)) {
+ U_ASSERT(canonicalID != NULL); // canocanilD must be non-NULL here
+
+ // Put the resolved canonical ID to the cache
+ umtx_lock(&gZoneMetaLock);
+ {
+ const UChar* idInCache = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
+ if (idInCache == NULL) {
+ const UChar* key = ZoneMeta::findTimeZoneID(tzid);
+ U_ASSERT(key != NULL);
+ if (key != NULL) {
+ idInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)key, (void *)canonicalID, &status);
+ U_ASSERT(idInCache == NULL);
+ }
+ }
+ if (U_SUCCESS(status) && isInputCanonical) {
+ // Also put canonical ID itself into the cache if not exist
+ const UChar *canonicalInCache = (const UChar*)uhash_get(gCanonicalIDCache, canonicalID);
+ if (canonicalInCache == NULL) {
+ canonicalInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)canonicalID, (void *)canonicalID, &status);
+ U_ASSERT(canonicalInCache == NULL);
+ }
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+ }
+
+ return canonicalID;
+}
+
+UnicodeString& U_EXPORT2
+ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) {
+ const UChar *canonicalID = getCanonicalCLDRID(tzid, status);
+ if (U_FAILURE(status) || canonicalID == NULL) {
+ systemID.setToBogus();
+ return systemID;
+ }
+ systemID.setTo(TRUE, canonicalID, -1);
+ return systemID;
+}
+
+const UChar* U_EXPORT2
+ZoneMeta::getCanonicalCLDRID(const TimeZone& tz) {
+ if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL) {
+ // short cut for OlsonTimeZone
+ const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz;
+ return otz->getCanonicalID();
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString tzID;
+ return getCanonicalCLDRID(tz.getID(tzID), status);
+}
+
+
+
+UnicodeString& U_EXPORT2
+ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
+ const UChar *region = TimeZone::getRegion(tzid);
+ if (region != NULL && u_strcmp(gWorld, region) != 0) {
+ canonicalCountry.setTo(region, -1);
+ } else {
+ canonicalCountry.setToBogus();
+ }
+ return canonicalCountry;
+}
+
+UnicodeString& U_EXPORT2
+ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
+ // Get canonical country for the zone
+ const UChar *region = TimeZone::getRegion(tzid);
+ if (region == NULL || u_strcmp(gWorld, region) == 0) {
+ // special case - unknown or "001"
+ country.setToBogus();
+ return country;
+ }
+
+ // Checking the cached results
+ UErrorCode status = U_ZERO_ERROR;
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gCountryInfoVectorsInitialized, initialized);
+ if (!initialized) {
+ // Create empty vectors
+ umtx_lock(&gZoneMetaLock);
+ {
+ if (!gCountryInfoVectorsInitialized) {
+ // No deleters for these UVectors, it's a reference to a resource bundle string.
+ gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status);
+ if (gSingleZoneCountries == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status);
+ if (gMultiZonesCountries == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (U_SUCCESS(status)) {
+ gCountryInfoVectorsInitialized = TRUE;
+ } else {
+ delete gSingleZoneCountries;
+ delete gMultiZonesCountries;
+ }
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ if (U_FAILURE(status)) {
+ country.setToBogus();
+ return country;
+ }
+ }
+
+ // Check if it was already cached
+ UBool cached = FALSE;
+ UBool multiZones = FALSE;
+ umtx_lock(&gZoneMetaLock);
+ {
+ multiZones = cached = gMultiZonesCountries->contains((void*)region);
+ if (!multiZones) {
+ cached = gSingleZoneCountries->contains((void*)region);
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ if (!cached) {
+ // We need to go through all zones associated with the region.
+ // This is relatively heavy operation.
+
+ U_ASSERT(u_strlen(region) == 2);
+
+ char buf[] = {0, 0, 0};
+ u_UCharsToChars(region, buf, 2);
+
+ StringEnumeration *ids = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION, buf, NULL, status);
+ int32_t idsLen = ids->count(status);
+ if (U_SUCCESS(status) && idsLen > 1) {
+ // multiple canonical zones are available for the region
+ multiZones = TRUE;
+ }
+ if (U_FAILURE(status)) {
+ // no single country by default for any error cases
+ multiZones = TRUE;
+ }
+ delete ids;
+
+ // Cache the result
+ umtx_lock(&gZoneMetaLock);
+ {
+ UErrorCode ec = U_ZERO_ERROR;
+ if (multiZones) {
+ if (!gMultiZonesCountries->contains((void*)region)) {
+ gMultiZonesCountries->addElement((void*)region, ec);
+ }
+ } else {
+ if (!gSingleZoneCountries->contains((void*)region)) {
+ gSingleZoneCountries->addElement((void*)region, ec);
+ }
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+ }
+
+ if (multiZones) {
+ country.setToBogus();
+ } else {
+ country.setTo(region, -1);
+ }
+ return country;
+}
+
+UnicodeString& U_EXPORT2
+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.setToBogus();
+ }
+ return result;
+}
+
+const UVector* U_EXPORT2
+ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
+ UErrorCode status = U_ZERO_ERROR;
+ UChar tzidUChars[ZID_KEY_MAX + 1];
+ tzid.extract(tzidUChars, ZID_KEY_MAX + 1, status);
+ if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
+ return NULL;
+ }
+
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gOlsonToMetaInitialized, initialized);
+ if (!initialized) {
+ UHashtable *tmpOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ uhash_setKeyDeleter(tmpOlsonToMeta, deleteUCharString);
+ uhash_setValueDeleter(tmpOlsonToMeta, deleteUVector);
+
+ umtx_lock(&gZoneMetaLock);
+ {
+ if (!gOlsonToMetaInitialized) {
+ gOlsonToMeta = tmpOlsonToMeta;
+ tmpOlsonToMeta = NULL;
+ gOlsonToMetaInitialized = TRUE;
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ // OK to call the following multiple times with the same function
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+ if (tmpOlsonToMeta != NULL) {
+ uhash_close(tmpOlsonToMeta);
+ }
+ }
+
+ // get the mapping from cache
+ const UVector *result = NULL;
+
+ umtx_lock(&gZoneMetaLock);
+ {
+ result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ if (result != NULL) {
+ return result;
+ }
+
+ // miss the cache - create new one
+ UVector *tmpResult = createMetazoneMappings(tzid);
+ if (tmpResult == NULL) {
+ // not available
+ return NULL;
+ }
+
+ // put the new one into the cache
+ umtx_lock(&gZoneMetaLock);
+ {
+ // make sure it's already created
+ result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
+ if (result == NULL) {
+ // add the one just created
+ int32_t tzidLen = tzid.length() + 1;
+ UChar *key = (UChar*)uprv_malloc(tzidLen * sizeof(UChar));
+ if (key == NULL) {
+ // memory allocation error.. just return NULL
+ result = NULL;
+ delete tmpResult;
+ } else {
+ tzid.extract(key, tzidLen, status);
+ uhash_put(gOlsonToMeta, key, tmpResult, &status);
+ if (U_FAILURE(status)) {
+ // delete the mapping
+ result = NULL;
+ delete tmpResult;
+ } else {
+ result = tmpResult;
+ }
+ }
+ } else {
+ // another thread already put the one
+ delete tmpResult;
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ return result;
+}
+
+UVector*
+ZoneMeta::createMetazoneMappings(const UnicodeString &tzid) {
+ UVector *mzMappings = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+
+ UnicodeString canonicalID;
+ UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
+ ures_getByKey(rb, gMetazoneInfo, rb, &status);
+ getCanonicalCLDRID(tzid, canonicalID, status);
+
+ if (U_SUCCESS(status)) {
+ char tzKey[ZID_KEY_MAX + 1];
+ int32_t tzKeyLen = canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV);
+ tzKey[tzKeyLen] = 0;
+
+ // tzid keys are using ':' as separators
+ char *p = tzKey;
+ while (*p) {
+ if (*p == '/') {
+ *p = ':';
+ }
+ p++;
+ }
+
+ ures_getByKey(rb, tzKey, rb, &status);
+
+ if (U_SUCCESS(status)) {
+ UResourceBundle *mz = NULL;
+ while (ures_hasNext(rb)) {
+ mz = ures_getNextResource(rb, mz, &status);
+
+ const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status);
+ const UChar *mz_from = gDefaultFrom;
+ const UChar *mz_to = gDefaultTo;
+
+ if (ures_getSize(mz) == 3) {
+ mz_from = ures_getStringByIndex(mz, 1, NULL, &status);
+ 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;
+ }
+ }
+ ures_close(mz);
+ if (U_FAILURE(status)) {
+ if (mzMappings != NULL) {
+ delete mzMappings;
+ mzMappings = NULL;
+ }
+ }
+ }
+ }
+ ures_close(rb);
+ return mzMappings;
+}
+
+UnicodeString& U_EXPORT2
+ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result) {
+ UErrorCode status = U_ZERO_ERROR;
+ const UChar *tzid = NULL;
+ int32_t tzidLen = 0;
+ char keyBuf[ZID_KEY_MAX + 1];
+ int32_t keyLen = 0;
+
+ if (mzid.length() > ZID_KEY_MAX) {
+ result.setToBogus();
+ return result;
+ }
+
+ keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX + 1, US_INV);
+ keyBuf[keyLen] = 0;
+
+ UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
+ ures_getByKey(rb, gMapTimezonesTag, rb, &status);
+ ures_getByKey(rb, keyBuf, rb, &status);
+
+ if (U_SUCCESS(status)) {
+ // check region mapping
+ if (region.length() == 2 || region.length() == 3) {
+ keyLen = region.extract(0, region.length(), keyBuf, ZID_KEY_MAX + 1, US_INV);
+ keyBuf[keyLen] = 0;
+ tzid = ures_getStringByKey(rb, keyBuf, &tzidLen, &status);
+ if (status == U_MISSING_RESOURCE_ERROR) {
+ status = U_ZERO_ERROR;
+ }
+ }
+ if (U_SUCCESS(status) && tzid == NULL) {
+ // try "001"
+ tzid = ures_getStringByKey(rb, gWorldTag, &tzidLen, &status);
+ }
+ }
+ ures_close(rb);
+
+ if (tzid == NULL) {
+ result.setToBogus();
+ } else {
+ result.setTo(tzid, tzidLen);
+ }
+
+ return result;
+}
+
+void
+ZoneMeta::initAvailableMetaZoneIDs () {
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gMetaZoneIDsInitialized, initialized);
+ if (!initialized) {
+ umtx_lock(&gZoneMetaLock);
+ {
+ if (!gMetaZoneIDsInitialized) {
+ UErrorCode status = U_ZERO_ERROR;
+ UHashtable *metaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
+ uhash_setKeyDeleter(metaZoneIDTable, uhash_deleteUnicodeString);
+ // No valueDeleter, because the vector maintain the value objects
+ UVector *metaZoneIDs = NULL;
+ if (U_SUCCESS(status)) {
+ metaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
+ if (metaZoneIDs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ } else {
+ uhash_close(metaZoneIDTable);
+ }
+ if (U_SUCCESS(status)) {
+ metaZoneIDs->setDeleter(uhash_freeBlock);
+
+ UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
+ UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ while (U_SUCCESS(status) && ures_hasNext(bundle)) {
+ ures_getNextResource(bundle, &res, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ const char *mzID = ures_getKey(&res);
+ int32_t len = uprv_strlen(mzID);
+ UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
+ if (uMzID == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ u_charsToUChars(mzID, uMzID, len);
+ uMzID[len] = 0;
+ UnicodeString *usMzID = new UnicodeString(uMzID);
+ if (uhash_get(metaZoneIDTable, usMzID) == NULL) {
+ metaZoneIDs->addElement((void *)uMzID, status);
+ uhash_put(metaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
+ } else {
+ uprv_free(uMzID);
+ delete usMzID;
+ }
+ }
+ if (U_SUCCESS(status)) {
+ gMetaZoneIDs = metaZoneIDs;
+ gMetaZoneIDTable = metaZoneIDTable;
+ gMetaZoneIDsInitialized = TRUE;
+ } else {
+ uhash_close(metaZoneIDTable);
+ delete metaZoneIDs;
+ }
+ ures_close(&res);
+ ures_close(bundle);
+ ures_close(rb);
+ }
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+ }
+}
+
+const UVector*
+ZoneMeta::getAvailableMetazoneIDs() {
+ initAvailableMetaZoneIDs();
+ return gMetaZoneIDs;
+}
+
+const UChar*
+ZoneMeta::findMetaZoneID(const UnicodeString& mzid) {
+ initAvailableMetaZoneIDs();
+ return (const UChar*)uhash_get(gMetaZoneIDTable, &mzid);
+}
+
+const UChar*
+ZoneMeta::findTimeZoneID(const UnicodeString& tzid) {
+ return TimeZone::findID(tzid);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.h b/Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.h
new file mode 100644
index 00000000000..085c2af023d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/zonemeta.h
@@ -0,0 +1,99 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2011, 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 OlsonToMetaMappingEntry {
+ const UChar *mzid; // const because it's a reference to a resource bundle string.
+ UDate from;
+ UDate to;
+} OlsonToMetaMappingEntry;
+
+class UVector;
+class TimeZone;
+
+class U_I18N_API ZoneMeta {
+public:
+ /**
+ * Return the canonical id for this tzid defined by CLDR, which might be the id itself.
+ * If the given system tzid is not known, U_ILLEGAL_ARGUMENT_ERROR is set in the status.
+ *
+ * Note: this internal API supports all known system IDs and "Etc/Unknown" (which is
+ * NOT a system ID).
+ */
+ static UnicodeString& U_EXPORT2 getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status);
+
+ /**
+ * Return the canonical id for this tzid defined by CLDR, which might be the id itself.
+ * This overload method returns a persistent const UChar*, which is guranteed to persist
+ * (a pointer to a resource).
+ */
+ static const UChar* U_EXPORT2 getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status);
+
+ /*
+ * Conveninent method returning CLDR canonical ID for the given time zone
+ */
+ static const UChar* U_EXPORT2 getCanonicalCLDRID(const TimeZone& tz);
+
+ /**
+ * 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& U_EXPORT2 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& U_EXPORT2 getSingleCountry(const UnicodeString &tzid, UnicodeString &country);
+
+ /**
+ * Returns a CLDR metazone ID for the given Olson tzid and time.
+ */
+ static UnicodeString& U_EXPORT2 getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result);
+ /**
+ * Returns an Olson ID for the ginve metazone and region
+ */
+ static UnicodeString& U_EXPORT2 getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result);
+
+ static const UVector* U_EXPORT2 getMetazoneMappings(const UnicodeString &tzid);
+
+ static const UVector* U_EXPORT2 getAvailableMetazoneIDs();
+
+ /**
+ * Returns the pointer to the persistent time zone ID string, or NULL if the given tzid is not in the
+ * tz database. This method is useful when you maintain persistent zone IDs without duplication.
+ */
+ static const UChar* U_EXPORT2 findTimeZoneID(const UnicodeString& tzid);
+
+ /**
+ * Returns the pointer to the persistent meta zone ID string, or NULL if the given mzid is not available.
+ * This method is useful when you maintain persistent meta zone IDs without duplication.
+ */
+ static const UChar* U_EXPORT2 findMetaZoneID(const UnicodeString& mzid);
+
+private:
+ ZoneMeta(); // Prevent construction.
+ static UVector* createMetazoneMappings(const UnicodeString &tzid);
+ static void initAvailableMetaZoneIDs();
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif // ZONEMETA_H
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/zrule.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/zrule.cpp
new file mode 100644
index 00000000000..82c31169f6c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/zrule.cpp
@@ -0,0 +1,149 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C API: Time zone rule classes
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "zrule.h"
+#include "unicode/tzrule.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/parsepos.h"
+
+U_NAMESPACE_USE
+
+/*********************************************************************
+ * ZRule API
+ *********************************************************************/
+
+U_CAPI void U_EXPORT2
+zrule_close(ZRule* rule) {
+ delete (TimeZoneRule*)rule;
+}
+
+U_CAPI UBool U_EXPORT2
+zrule_equals(const ZRule* rule1, const ZRule* rule2) {
+ return *(const TimeZoneRule*)rule1 == *(const TimeZoneRule*)rule2;
+}
+
+U_CAPI void U_EXPORT2
+zrule_getName(ZRule* rule, UChar* name, int32_t nameLength) {
+ UnicodeString s(nameLength==-1, name, nameLength);
+ s = ((TimeZoneRule*)rule)->TimeZoneRule::getName(s);
+ nameLength = s.length();
+ memcpy(name, s.getBuffer(), nameLength);
+ return;
+}
+
+U_CAPI int32_t U_EXPORT2
+zrule_getRawOffset(ZRule* rule) {
+ return ((TimeZoneRule*)rule)->TimeZoneRule::getRawOffset();
+}
+
+U_CAPI int32_t U_EXPORT2
+zrule_getDSTSavings(ZRule* rule) {
+ return ((TimeZoneRule*)rule)->TimeZoneRule::getDSTSavings();
+}
+
+U_CAPI UBool U_EXPORT2
+zrule_isEquivalentTo(ZRule* rule1, ZRule* rule2) {
+ return ((TimeZoneRule*)rule1)->TimeZoneRule::isEquivalentTo(*(TimeZoneRule*)rule2);
+}
+
+/*********************************************************************
+ * IZRule API
+ *********************************************************************/
+
+U_CAPI IZRule* U_EXPORT2
+izrule_open(const UChar* name, int32_t nameLength, int32_t rawOffset, int32_t dstSavings) {
+ UnicodeString s(nameLength==-1, name, nameLength);
+ return (IZRule*) new InitialTimeZoneRule(name, rawOffset, dstSavings);
+}
+
+U_CAPI void U_EXPORT2
+izrule_close(IZRule* rule) {
+ delete (InitialTimeZoneRule*)rule;
+}
+
+U_CAPI IZRule* U_EXPORT2
+izrule_clone(IZRule *rule) {
+ return (IZRule*) (((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::clone());
+}
+
+U_CAPI UBool U_EXPORT2
+izrule_equals(const IZRule* rule1, const IZRule* rule2) {
+ return *(const InitialTimeZoneRule*)rule1 == *(const InitialTimeZoneRule*)rule2;
+}
+
+U_CAPI void U_EXPORT2
+izrule_getName(IZRule* rule, UChar* & name, int32_t & nameLength) {
+ // UnicodeString s(nameLength==-1, name, nameLength);
+ UnicodeString s;
+ ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getName(s);
+ nameLength = s.length();
+ name = (UChar*)uprv_malloc(nameLength);
+ memcpy(name, s.getBuffer(), nameLength);
+ return;
+}
+
+U_CAPI int32_t U_EXPORT2
+izrule_getRawOffset(IZRule* rule) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getRawOffset();
+}
+
+U_CAPI int32_t U_EXPORT2
+izrule_getDSTSavings(IZRule* rule) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getDSTSavings();
+}
+
+U_CAPI UBool U_EXPORT2
+izrule_isEquivalentTo(IZRule* rule1, IZRule* rule2) {
+ return ((InitialTimeZoneRule*)rule1)->InitialTimeZoneRule::isEquivalentTo(*(InitialTimeZoneRule*)rule2);
+}
+
+U_CAPI UBool U_EXPORT2
+izrule_getFirstStart(IZRule* rule, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UDate& result) {
+ return ((const InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getFirstStart(prevRawOffset, prevDSTSavings, result);
+}
+
+U_CAPI UBool U_EXPORT2
+izrule_getFinalStart(IZRule* rule, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UDate& result) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getFinalStart(prevRawOffset, prevDSTSavings, result);
+}
+
+U_CAPI UBool U_EXPORT2
+izrule_getNextStart(IZRule* rule, UDate base, int32_t prevRawOffset,
+ int32_t prevDSTSavings, UBool inclusive, UDate& result) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getNextStart(base, prevRawOffset, prevDSTSavings, inclusive, result);
+}
+
+U_CAPI UBool U_EXPORT2
+izrule_getPreviousStart(IZRule* rule, UDate base, int32_t prevRawOffset,
+ int32_t prevDSTSavings, UBool inclusive, UDate& result) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getPreviousStart(base, prevRawOffset, prevDSTSavings, inclusive, result);
+}
+
+U_CAPI UClassID U_EXPORT2
+izrule_getStaticClassID(IZRule* rule) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getStaticClassID();
+}
+
+U_CAPI UClassID U_EXPORT2
+izrule_getDynamicClassID(IZRule* rule) {
+ return ((InitialTimeZoneRule*)rule)->InitialTimeZoneRule::getDynamicClassID();
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/zrule.h b/Build/source/libs/icu/icu-4.8.1/i18n/zrule.h
new file mode 100644
index 00000000000..52e90eaf160
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/zrule.h
@@ -0,0 +1,279 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef __ZRULE_H
+#define __ZRULE_H
+
+/**
+ * \file
+ * \brief C API: Time zone rule classes
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#ifndef UCNV_H
+
+/**
+ * A TimeZoneRule. Use the zrule_* API to manipulate. Create with
+ * zrule_open*, and destroy with zrule_close.
+ */
+struct ZRule;
+typedef struct ZRule ZRule;
+
+/**
+ * An InitialTimeZoneRule. Use the izrule_* API to manipulate. Create with
+ * izrule_open*, and destroy with izrule_close.
+ */
+struct IZRule;
+typedef struct IZRule IZRule;
+
+/**
+ * An AnnualTimeZoneRule. Use the azrule_* API to manipulate. Create with
+ * azrule_open*, and destroy with azrule_close.
+ */
+struct AZRule;
+typedef struct AZRule AZRule;
+
+#endif
+
+/*********************************************************************
+ * ZRule API
+ *********************************************************************/
+
+/**
+ * Disposes of the storage used by a ZRule object. This function should
+ * be called exactly once for objects returned by zrule_open*.
+ * @param set the object to dispose of
+ */
+U_CAPI void U_EXPORT2
+zrule_close(ZRule* rule);
+
+/**
+ * Returns true if rule1 is identical to rule2
+ * and vis versa.
+ * @param rule1 to be checked for containment
+ * @param rule2 to be checked for containment
+ * @return true if the test condition is met
+ */
+U_CAPI UBool U_EXPORT2
+zrule_equals(const ZRule* rule1, const ZRule* rule2);
+
+/**
+ * Fills in "name" with the name of this time zone.
+ * @param rule, the Zrule to use
+ * @param name Receives the name of this time zone.
+ * @param nameLength, length of the returned name
+ */
+U_CAPI void U_EXPORT2
+zrule_getName(ZRule* rule, UChar* name, int32_t nameLength);
+
+/**
+ * Gets the standard time offset.
+ * @param rule, the Zrule to use
+ * @return The standard time offset from UTC in milliseconds.
+ */
+U_CAPI int32_t U_EXPORT2
+zrule_getRawOffset(ZRule* rule);
+
+/**
+ * Gets the amount of daylight saving delta time from the standard time.
+ * @param rule, the Zrule to use
+ * @return The amount of daylight saving offset used by this rule
+ * in milliseconds.
+ */
+U_CAPI int32_t U_EXPORT2
+zrule_getDSTSavings(ZRule* rule);
+
+/**
+ * Returns if this rule represents the same rule and offsets as another.
+ * When two ZRule objects differ only its names, this method
+ * returns true.
+ * @param rule1 to be checked for containment
+ * @param rule2 to be checked for containment
+ * @return true if the other <code>TimeZoneRule</code> is the same as this one.
+ */
+U_CAPI UBool U_EXPORT2
+zrule_isEquivalentTo(ZRule* rule1, ZRule* rule2);
+
+/*********************************************************************
+ * IZRule API
+ *********************************************************************/
+
+/**
+ * Constructs an IZRule 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 nameLength The length of 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.
+ */
+U_CAPI IZRule* U_EXPORT2
+izrule_open(const UChar* name, int32_t nameLength, int32_t rawOffset, int32_t dstSavings);
+
+/**
+ * Disposes of the storage used by a IZRule object. This function should
+ * be called exactly once for objects returned by izrule_open*.
+ * @param set the object to dispose of
+ */
+U_CAPI void U_EXPORT2
+izrule_close(IZRule* rule);
+
+/**
+ * Returns a copy of this object.
+ * @param rule the original IZRule
+ * @return the newly allocated copy of the IZRule
+ */
+U_CAPI IZRule* U_EXPORT2
+izrule_clone(IZRule *rule);
+
+/**
+ * Returns true if rule1 is identical to rule2
+ * and vis versa.
+ * @param rule1 to be checked for containment
+ * @param rule2 to be checked for containment
+ * @return true if the test condition is met
+ */
+U_CAPI UBool U_EXPORT2
+izrule_equals(const IZRule* rule1, const IZRule* rule2);
+
+/**
+ * Fills in "name" with the name of this time zone.
+ * @param rule, the IZrule to use
+ * @param name Receives the name of this time zone.
+ * @param nameLength, length of the returned name
+ */
+U_CAPI void U_EXPORT2
+izrule_getName(IZRule* rule, UChar* & name, int32_t & nameLength);
+
+/**
+ * Gets the standard time offset.
+ * @param rule, the IZrule to use
+ * @return The standard time offset from UTC in milliseconds.
+ */
+U_CAPI int32_t U_EXPORT2
+izrule_getRawOffset(IZRule* rule);
+
+/**
+ * Gets the amount of daylight saving delta time from the standard time.
+ * @param rule, the IZrule to use
+ * @return The amount of daylight saving offset used by this rule
+ * in milliseconds.
+ */
+U_CAPI int32_t U_EXPORT2
+izrule_getDSTSavings(IZRule* rule);
+
+/**
+ * Returns if this rule represents the same rule and offsets as another.
+ * When two IZRule objects differ only its names, this method
+ * returns true.
+ * @param rule1 to be checked for containment
+ * @param rule2 to be checked for containment
+ * @return true if the other <code>TimeZoneRule</code> is the same as this one.
+ */
+U_CAPI UBool U_EXPORT2
+izrule_isEquivalentTo(IZRule* rule1, IZRule* rule2);
+
+/**
+ * Gets the very first time when this rule takes effect.
+ * @param rule The IZrule to use
+ * @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.
+ */
+U_CAPI UBool U_EXPORT2
+izrule_getFirstStart(IZRule* rule, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UDate& result);
+
+/**
+ * Gets the final time when this rule takes effect.
+ * @param rule The IZrule to use
+ * @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.
+ */
+U_CAPI UBool U_EXPORT2
+izrule_getFinalStart(IZRule* rule, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UDate& result);
+
+/**
+ * Gets the first time when this rule takes effect after the specified time.
+ * @param rule The IZrule to use
+ * @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.
+ */
+U_CAPI UBool U_EXPORT2
+izrule_getNextStart(IZRule* rule, UDate base, int32_t prevRawOffset,
+ int32_t prevDSTSavings, UBool inclusive, UDate& result);
+
+/**
+ * Gets the most recent time when this rule takes effect before the specified time.
+ * @param rule The IZrule to use
+ * @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.
+ */
+U_CAPI UBool U_EXPORT2
+izrule_getPreviousStart(IZRule* rule, UDate base, int32_t prevRawOffset,
+ int32_t prevDSTSavings, UBool inclusive, UDate& result);
+
+
+/**
+ * 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>
+ * @param rule The IZrule to use
+ * @return The class ID for all objects of this class.
+ */
+U_CAPI UClassID U_EXPORT2
+izrule_getStaticClassID(IZRule* rule);
+
+/**
+ * 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.
+ *
+ * @param rule The IZrule to use
+ * @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.
+ */
+U_CAPI UClassID U_EXPORT2
+izrule_getDynamicClassID(IZRule* rule);
+
+#endif
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ztrans.cpp b/Build/source/libs/icu/icu-4.8.1/i18n/ztrans.cpp
new file mode 100644
index 00000000000..58f2e12476d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ztrans.cpp
@@ -0,0 +1,101 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C API: Time zone transition classes
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "ztrans.h"
+#include "unicode/tztrans.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/parsepos.h"
+
+U_NAMESPACE_USE
+
+U_CAPI ZTrans* U_EXPORT2
+ztrans_open(UDate time, const void* from, const void* to){
+ return (ZTrans*) new TimeZoneTransition(time,*(TimeZoneRule*)from,*(TimeZoneRule*)to);
+}
+
+U_CAPI ZTrans* U_EXPORT2
+ztrans_openEmpty() {
+ return (ZTrans*) new TimeZoneTransition();
+}
+
+U_CAPI void U_EXPORT2
+ztrans_close(ZTrans *trans) {
+ delete (TimeZoneTransition*)trans;
+}
+
+U_CAPI ZTrans* U_EXPORT2
+ztrans_clone(ZTrans *trans) {
+ return (ZTrans*) (((TimeZoneTransition*)trans)->TimeZoneTransition::clone());
+}
+
+U_CAPI UBool U_EXPORT2
+ztrans_equals(const ZTrans* trans1, const ZTrans* trans2){
+ return *(const TimeZoneTransition*)trans1 == *(const TimeZoneTransition*)trans2;
+}
+
+U_CAPI UDate U_EXPORT2
+ztrans_getTime(ZTrans* trans) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::getTime();
+}
+
+U_CAPI void U_EXPORT2
+ztrans_setTime(ZTrans* trans, UDate time) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::setTime(time);
+}
+
+U_CAPI void* U_EXPORT2
+ztrans_getFrom(ZTrans* & trans) {
+ return (void*) (((TimeZoneTransition*)trans)->TimeZoneTransition::getFrom());
+}
+
+U_CAPI void U_EXPORT2
+ztrans_setFrom(ZTrans* trans, const void* from) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::setFrom(*(TimeZoneRule*)from);
+}
+
+U_CAPI void U_EXPORT2
+ztrans_adoptFrom(ZTrans* trans, void* from) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::adoptFrom((TimeZoneRule*)from);
+}
+
+U_CAPI void* U_EXPORT2
+ztrans_getTo(ZTrans* trans){
+ return (void*) (((TimeZoneTransition*)trans)->TimeZoneTransition::getTo());
+}
+
+U_CAPI void U_EXPORT2
+ztrans_setTo(ZTrans* trans, const void* to) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::setTo(*(TimeZoneRule*)to);
+}
+
+U_CAPI void U_EXPORT2
+ztrans_adoptTo(ZTrans* trans, void* to) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::adoptTo((TimeZoneRule*)to);
+}
+
+U_CAPI UClassID U_EXPORT2
+ztrans_getStaticClassID(ZTrans* trans) {
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::getStaticClassID();
+}
+
+U_CAPI UClassID U_EXPORT2
+ztrans_getDynamicClassID(ZTrans* trans){
+ return ((TimeZoneTransition*)trans)->TimeZoneTransition::getDynamicClassID();
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.8.1/i18n/ztrans.h b/Build/source/libs/icu/icu-4.8.1/i18n/ztrans.h
new file mode 100644
index 00000000000..1a0d10c6f83
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.8.1/i18n/ztrans.h
@@ -0,0 +1,172 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+#ifndef __ZTRANS_H
+#define __ZTRANS_H
+
+/**
+ * \file
+ * \brief C API: Time zone transition classes
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#ifndef UCNV_H
+
+/**
+ * A TimeZoneTransition. Use the ztrans_* API to manipulate. Create with
+ * ztrans_open*, and destroy with ztrans_close.
+ */
+struct ZTrans;
+typedef struct ZTrans ZTrans;
+
+#endif
+
+/**
+ * Constructs a time zone transition 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.
+ */
+U_CAPI ZTrans* U_EXPORT2
+ztrans_open(UDate time, const void* from, const void* to);
+
+/**
+ * Constructs an empty <code>TimeZoneTransition</code>
+ */
+U_CAPI ZTrans* U_EXPORT2
+ztrans_openEmpty();
+
+/**
+ * Disposes of the storage used by a ZTrans object. This function should
+ * be called exactly once for objects returned by ztrans_open*.
+ * @param trans the object to dispose of
+ */
+U_CAPI void U_EXPORT2
+ztrans_close(ZTrans *trans);
+
+/**
+ * Returns a copy of this object.
+ * @param rule the original ZRule
+ * @return the newly allocated copy of the ZRule
+ */
+U_CAPI ZTrans* U_EXPORT2
+ztrans_clone(ZTrans *trans);
+
+/**
+ * Returns true if trans1 is identical to trans2
+ * and vis versa.
+ * @param trans1 to be checked for containment
+ * @param trans2 to be checked for containment
+ * @return true if the test condition is met
+ */
+U_CAPI UBool U_EXPORT2
+ztrans_equals(const ZTrans* trans1, const ZTrans* trans2);
+
+/**
+ * Returns the time of transition in milliseconds.
+ * param trans, the transition to use
+ * @return The time of the transition in milliseconds since the 1970 Jan 1 epoch time.
+ */
+U_CAPI UDate U_EXPORT2
+ztrans_getTime(ZTrans* trans);
+
+/**
+ * Sets the time of transition in milliseconds.
+ * param trans, the transition to use
+ * @param time The time of the transition in milliseconds since the 1970 Jan 1 epoch time.
+ */
+U_CAPI void U_EXPORT2
+ztrans_setTime(ZTrans* trans, UDate time);
+
+/**
+ * Returns the rule used before the transition.
+ * param trans, the transition to use
+ * @return The time zone rule used after the transition.
+ */
+U_CAPI void* U_EXPORT2
+ztrans_getFrom(ZTrans* & trans);
+
+/**
+ * Sets the rule used before the transition. The caller remains
+ * responsible for deleting the TimeZoneRule object.
+ * param trans, the transition to use
+ * param trans, the transition to use
+ * @param from The time zone rule used before the transition.
+ */
+U_CAPI void U_EXPORT2
+ztrans_setFrom(ZTrans* trans, const void* from);
+
+/**
+ * Adopts the rule used before the transition. The caller must
+ * not delete the TimeZoneRule object passed in.
+ * param trans, the transition to use
+ * @param from The time zone rule used before the transition.
+ */
+U_CAPI void U_EXPORT2
+ztrans_adoptFrom(ZTrans* trans, void* from);
+
+/**
+ * Returns the rule used after the transition.
+ * param trans, the transition to use
+ * @return The time zone rule used after the transition.
+ */
+U_CAPI void* U_EXPORT2
+ztrans_getTo(ZTrans* trans);
+
+/**
+ * Sets the rule used after the transition. The caller remains
+ * responsible for deleting the TimeZoneRule object.
+ * param trans, the transition to use
+ * @param to The time zone rule used after the transition.
+ */
+U_CAPI void U_EXPORT2
+ztrans_setTo(ZTrans* trans, const void* to);
+
+/**
+ * Adopts the rule used after the transition. The caller must
+ * not delete the TimeZoneRule object passed in.
+ * param trans, the transition to use
+ * @param to The time zone rule used after the transition.
+ */
+U_CAPI void U_EXPORT2
+ztrans_adoptTo(ZTrans* trans, void* to);
+
+/**
+ * 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>
+ * param trans, the transition to use
+ * @return The class ID for all objects of this class.
+ */
+U_CAPI UClassID U_EXPORT2
+ztrans_getStaticClassID(ZTrans* trans);
+
+/**
+ * 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.
+ *
+ * param trans, the transition to use
+ * @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.
+ */
+U_CAPI UClassID U_EXPORT2
+ztrans_getDynamicClassID(ZTrans* trans);
+
+#endif
+
+#endif