summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-4.6/i18n
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2010-12-03 09:05:05 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2010-12-03 09:05:05 +0000
commite04c6a878f5044d36eaa95d4c2318e0381a32998 (patch)
tree5b7c36578140e48c0114863004c8375ea55db21d /Build/source/libs/icu/icu-4.6/i18n
parentfa438554bd1a061515cd8f5f46fbe311ff08dcd6 (diff)
icu 4.6
git-svn-id: svn://tug.org/texlive/trunk@20645 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/icu/icu-4.6/i18n')
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/Makefile.in187
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/anytrans.cpp386
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/anytrans.h129
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/astro.cpp1590
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/astro.h755
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/basictz.cpp560
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/bms.cpp153
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/bmsearch.cpp817
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/bocsu.c191
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/bocsu.h162
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/brktrans.cpp188
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/brktrans.h113
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/buddhcal.cpp212
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/buddhcal.h243
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/calendar.cpp3374
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/casetrn.cpp191
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/casetrn.h104
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/cecal.cpp149
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/cecal.h134
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/chnsecal.cpp865
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/chnsecal.h294
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/choicfmt.cpp764
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/coleitr.cpp485
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/coll.cpp866
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/colldata.cpp1100
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/coptccal.cpp178
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/coptccal.h272
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/cpdtrans.cpp616
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/cpdtrans.h248
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csdetect.cpp414
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csdetect.h56
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csmatch.cpp61
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csmatch.h44
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csr2022.cpp175
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csr2022.h86
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrecog.cpp28
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrecog.h42
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrmbcs.cpp519
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrmbcs.h205
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrsbcs.cpp1350
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrsbcs.h427
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrucode.cpp146
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrucode.h106
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrutf8.cpp111
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/csrutf8.h42
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/curramt.cpp50
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/currfmt.cpp72
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/currfmt.h101
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/currpinf.cpp384
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/currunit.cpp62
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/datefmt.cpp513
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dcfmtsym.cpp449
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/decContext.c435
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/decContext.h267
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/decNumber.c8143
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/decNumber.h196
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/decNumberLocal.h735
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/decimfmt.cpp4615
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/digitlst.cpp861
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/digitlst.h399
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtfmtsym.cpp1576
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtitv_impl.h93
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtitvfmt.cpp1432
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtitvinf.cpp660
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtptngen.cpp2159
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtptngen_impl.h259
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/dtrule.cpp139
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/esctrn.cpp179
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/esctrn.h142
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ethpccal.cpp214
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ethpccal.h300
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/fmtable.cpp852
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/fmtable_cnv.cpp44
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/format.cpp213
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/fphdlimp.cpp120
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/fphdlimp.h73
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/fpositer.cpp109
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/funcrepl.cpp125
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/funcrepl.h123
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/gregocal.cpp1356
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/gregoimp.cpp328
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/gregoimp.h364
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/hebrwcal.cpp758
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/hebrwcal.h486
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/i18n.rc108
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj1472
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj.filters955
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/indiancal.cpp449
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/indiancal.h372
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/inputext.cpp164
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/inputext.h61
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/islamcal.cpp545
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/islamcal.h463
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/japancal.cpp531
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/japancal.h217
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/locdspnm.cpp694
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/measfmt.cpp44
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/measure.cpp67
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/msgfmt.cpp1858
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/msgfmt_impl.h43
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/name2uni.cpp254
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/name2uni.h91
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfrlist.h97
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfrs.cpp946
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfrs.h106
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfrule.cpp1476
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfrule.h114
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfsubs.cpp1317
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nfsubs.h266
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nortrans.cpp175
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nortrans.h100
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nultrans.cpp36
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/nultrans.h71
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/numfmt.cpp1299
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/numsys.cpp247
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/olsontz.cpp1056
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/olsontz.h427
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/persncal.cpp465
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/persncal.h364
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp537
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/plurrule.cpp1212
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/plurrule_impl.h221
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/quant.cpp146
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/quant.h128
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbnf.cpp1615
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt.cpp295
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt.h473
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_data.cpp117
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_data.h152
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_pars.cpp1732
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_pars.h355
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_rule.cpp556
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_rule.h308
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_set.cpp466
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbt_set.h165
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rbtz.cpp934
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regexcmp.cpp4323
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regexcmp.h229
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regexcst.h504
-rwxr-xr-xBuild/source/libs/icu/icu-4.6/i18n/regexcst.pl328
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regexcst.txt467
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regeximp.h357
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regexst.cpp294
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regexst.h58
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regextxt.cpp45
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/regextxt.h48
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/reldtfmt.cpp472
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/reldtfmt.h301
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/rematch.cpp6073
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/remtrans.cpp68
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/remtrans.h78
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/repattrn.cpp839
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/search.cpp443
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/selfmt.cpp447
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/selfmtimpl.h97
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/simpletz.cpp1221
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/smpdtfmt.cpp3295
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/sortkey.cpp403
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/strmatch.cpp289
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/strmatch.h254
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/strrepl.cpp328
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/strrepl.h165
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/stsearch.cpp509
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/taiwncal.cpp220
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/taiwncal.h225
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tblcoll.cpp732
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/timezone.cpp1387
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/titletrn.cpp167
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/titletrn.h90
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tmunit.cpp117
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tmutamt.cpp76
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tmutfmt.cpp874
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tolowtrn.cpp65
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tolowtrn.h74
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/toupptrn.cpp65
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/toupptrn.h74
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/translit.cpp1644
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/transreg.cpp1359
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/transreg.h462
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tridpars.cpp938
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tridpars.h361
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tzrule.cpp627
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/tztrans.cpp146
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucal.cpp687
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucln_in.c60
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucln_in.h59
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol.cpp8593
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_bld.cpp1417
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_bld.h59
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_cnt.cpp587
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_cnt.h102
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_elm.cpp2064
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_elm.h146
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_imp.h1133
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_res.cpp1295
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_sit.cpp911
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_tok.cpp2452
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_tok.h211
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_wgt.cpp564
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucol_wgt.h70
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucoleitr.cpp784
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucsdet.cpp180
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucurr.cpp2258
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ucurrimp.h59
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/udat.cpp962
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/udatpg.cpp271
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ulocdata.c341
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/umsg.cpp706
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/umsg_imp.h45
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unesctrn.cpp290
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unesctrn.h110
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uni2name.cpp120
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uni2name.h87
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/basictz.h210
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/bms.h274
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/bmsearch.h226
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/calendar.h2252
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/choicfmt.h749
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/coleitr.h400
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/coll.h1113
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/colldata.h452
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/curramt.h130
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/currpinf.h259
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/currunit.h117
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/datefmt.h751
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/dcfmtsym.h460
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/decimfmt.h2310
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/dtfmtsym.h755
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/dtitvfmt.h970
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/dtitvinf.h527
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/dtptngen.h474
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/dtrule.h250
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/fieldpos.h291
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/fmtable.h673
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/format.h303
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/fpositer.h120
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/gregocal.h823
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/locdspnm.h188
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/measfmt.h77
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/measunit.h71
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/measure.h137
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/msgfmt.h961
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/numfmt.h1051
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/numsys.h191
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/plurfmt.h549
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/plurrule.h299
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/rbnf.h1059
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/rbtz.h361
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/regex.h1772
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/search.h569
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/selfmt.h377
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/simpletz.h927
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/smpdtfmt.h1207
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/sortkey.h324
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/stsearch.h518
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/tblcoll.h966
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/timezone.h777
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/tmunit.h149
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/tmutamt.h168
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/tmutfmt.h272
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/translit.h1320
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/tzrule.h828
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/tztrans.h195
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/ucal.h1285
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/ucol.h1227
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/ucoleitr.h330
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/ucsdet.h370
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/ucurr.h316
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/udat.h997
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/udatpg.h586
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/uldnames.h270
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/ulocdata.h263
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/umsg.h709
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/unirepl.h97
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/unum.h999
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/uregex.h1451
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/usearch.h829
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/uspoof.h887
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/utmscale.h481
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/utrans.h603
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unicode/vtzone.h455
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/unum.cpp947
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uregex.cpp1910
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uregexc.cpp40
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/usearch.cpp4749
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof.cpp827
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_build.cpp85
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_conf.cpp600
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_conf.h132
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.cpp962
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.h411
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_wsconf.cpp435
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/uspoof_wsconf.h70
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/usrchimp.h140
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/utmscale.c114
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/utrans.cpp495
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/vtzone.cpp2625
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/vzone.cpp185
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/vzone.h386
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/windtfmt.cpp321
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/windtfmt.h149
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/winnmfmt.cpp354
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/winnmfmt.h168
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/wintzimpl.cpp157
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/wintzimpl.h37
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/zonemeta.cpp650
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/zonemeta.h68
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/zrule.cpp149
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/zrule.h302
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/zstrfmt.cpp2228
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/zstrfmt.h526
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ztrans.cpp101
-rw-r--r--Build/source/libs/icu/icu-4.6/i18n/ztrans.h188
313 files changed, 196015 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-4.6/i18n/Makefile.in b/Build/source/libs/icu/icu-4.6/i18n/Makefile.in
new file mode 100644
index 00000000000..a23e5d9df39
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/Makefile.in
@@ -0,0 +1,187 @@
+#******************************************************************************
+#
+# Copyright (C) 1998-2010, 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 zstrfmt.o plurrule.o plurfmt.o selfmt.o dtitvfmt.o dtitvinf.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 \
+ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
+decNumber.o decContext.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.6/i18n/anytrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/anytrans.cpp
new file mode 100644
index 00000000000..7ce9ca71584
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/anytrans.h b/Build/source/libs/icu/icu-4.6/i18n/anytrans.h
new file mode 100644
index 00000000000..228ccbe03af
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/astro.cpp b/Build/source/libs/icu/icu-4.6/i18n/astro.cpp
new file mode 100644
index 00000000000..95ddfa3d757
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/astro.h b/Build/source/libs/icu/icu-4.6/i18n/astro.h
new file mode 100644
index 00000000000..cd20b6cf257
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/basictz.cpp b/Build/source/libs/icu/icu-4.6/i18n/basictz.cpp
new file mode 100644
index 00000000000..6b4889a216c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/bms.cpp b/Build/source/libs/icu/icu-4.6/i18n/bms.cpp
new file mode 100644
index 00000000000..99a45896c78
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/bms.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2008-2009, 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)
+{
+ 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.6/i18n/bmsearch.cpp b/Build/source/libs/icu/icu-4.6/i18n/bmsearch.cpp
new file mode 100644
index 00000000000..d7aa5c82859
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/bmsearch.cpp
@@ -0,0 +1,817 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2010, 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) {
+ 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.6/i18n/bocsu.c b/Build/source/libs/icu/icu-4.6/i18n/bocsu.c
new file mode 100644
index 00000000000..d4c6ab86ec8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/bocsu.c
@@ -0,0 +1,191 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: bocsu.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Author: Markus W. Scherer
+*
+* Modification history:
+* 05/18/2001 weiv Made into separate module
+*/
+
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "bocsu.h"
+
+/*
+ * encode one difference value -0x10ffff..+0x10ffff in 1..3 bytes,
+ * preserving lexical order
+ */
+U_CFUNC uint8_t *
+u_writeDiff(int32_t diff, uint8_t *p) {
+ if(diff>=SLOPE_REACH_NEG_1) {
+ if(diff<=SLOPE_REACH_POS_1) {
+ *p++=(uint8_t)(SLOPE_MIDDLE+diff);
+ } else if(diff<=SLOPE_REACH_POS_2) {
+ *p++=(uint8_t)(SLOPE_START_POS_2+(diff/SLOPE_TAIL_COUNT));
+ *p++=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ } else if(diff<=SLOPE_REACH_POS_3) {
+ p[2]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ diff/=SLOPE_TAIL_COUNT;
+ p[1]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ *p=(uint8_t)(SLOPE_START_POS_3+(diff/SLOPE_TAIL_COUNT));
+ p+=3;
+ } else {
+ p[3]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ diff/=SLOPE_TAIL_COUNT;
+ p[2]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ diff/=SLOPE_TAIL_COUNT;
+ p[1]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ *p=SLOPE_MAX;
+ p+=4;
+ }
+ } else {
+ int32_t m;
+
+ if(diff>=SLOPE_REACH_NEG_2) {
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ *p++=(uint8_t)(SLOPE_START_NEG_2+diff);
+ *p++=(uint8_t)(SLOPE_MIN+m);
+ } else if(diff>=SLOPE_REACH_NEG_3) {
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[2]=(uint8_t)(SLOPE_MIN+m);
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[1]=(uint8_t)(SLOPE_MIN+m);
+ *p=(uint8_t)(SLOPE_START_NEG_3+diff);
+ p+=3;
+ } else {
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[3]=(uint8_t)(SLOPE_MIN+m);
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[2]=(uint8_t)(SLOPE_MIN+m);
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[1]=(uint8_t)(SLOPE_MIN+m);
+ *p=SLOPE_MIN;
+ p+=4;
+ }
+ }
+ return p;
+}
+
+/* How many bytes would writeDiff() write? */
+static int32_t
+lengthOfDiff(int32_t diff) {
+ if(diff>=SLOPE_REACH_NEG_1) {
+ if(diff<=SLOPE_REACH_POS_1) {
+ return 1;
+ } else if(diff<=SLOPE_REACH_POS_2) {
+ return 2;
+ } else if(diff<=SLOPE_REACH_POS_3) {
+ return 3;
+ } else {
+ return 4;
+ }
+ } else {
+ if(diff>=SLOPE_REACH_NEG_2) {
+ return 2;
+ } else if(diff>=SLOPE_REACH_NEG_3) {
+ return 3;
+ } else {
+ return 4;
+ }
+ }
+}
+
+/*
+ * Encode the code points of a string as
+ * a sequence of byte-encoded differences (slope detection),
+ * preserving lexical order.
+ *
+ * Optimize the difference-taking for runs of Unicode text within
+ * small scripts:
+ *
+ * Most small scripts are allocated within aligned 128-blocks of Unicode
+ * code points. Lexical order is preserved if "prev" is always moved
+ * into the middle of such a block.
+ *
+ * Additionally, "prev" is moved from anywhere in the Unihan
+ * area into the middle of that area.
+ * Note that the identical-level run in a sort key is generated from
+ * NFD text - there are never Hangul characters included.
+ */
+U_CFUNC int32_t
+u_writeIdenticalLevelRun(const UChar *s, int32_t length, uint8_t *p) {
+ uint8_t *p0;
+ int32_t c, prev;
+ int32_t i;
+
+ prev=0;
+ p0=p;
+ i=0;
+ while(i<length) {
+ if(prev<0x4e00 || prev>=0xa000) {
+ prev=(prev&~0x7f)-SLOPE_REACH_NEG_1;
+ } else {
+ /*
+ * Unihan U+4e00..U+9fa5:
+ * double-bytes down from the upper end
+ */
+ prev=0x9fff-SLOPE_REACH_POS_2;
+ }
+
+ UTF_NEXT_CHAR(s, i, length, c);
+ p=u_writeDiff(c-prev, p);
+ prev=c;
+ }
+ return (int32_t)(p-p0);
+}
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRunTwoChars(UChar32 first, UChar32 second, uint8_t *p) {
+ uint8_t *p0 = p;
+ if(first<0x4e00 || first>=0xa000) {
+ first=(first&~0x7f)-SLOPE_REACH_NEG_1;
+ } else {
+ /*
+ * Unihan U+4e00..U+9fa5:
+ * double-bytes down from the upper end
+ */
+ first=0x9fff-SLOPE_REACH_POS_2;
+ }
+
+ p=u_writeDiff(second-first, p);
+ return (int32_t)(p-p0);
+}
+
+/* How many bytes would writeIdenticalLevelRun() write? */
+U_CFUNC int32_t
+u_lengthOfIdenticalLevelRun(const UChar *s, int32_t length) {
+ int32_t c, prev;
+ int32_t i, runLength;
+
+ prev=0;
+ runLength=0;
+ i=0;
+ while(i<length) {
+ if(prev<0x4e00 || prev>=0xa000) {
+ prev=(prev&~0x7f)-SLOPE_REACH_NEG_1;
+ } else {
+ /*
+ * Unihan U+4e00..U+9fa5:
+ * double-bytes down from the upper end
+ */
+ prev=0x9fff-SLOPE_REACH_POS_2;
+ }
+
+ UTF_NEXT_CHAR(s, i, length, c);
+ runLength+=lengthOfDiff(c-prev);
+ prev=c;
+ }
+ return runLength;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/bocsu.h b/Build/source/libs/icu/icu-4.6/i18n/bocsu.h
new file mode 100644
index 00000000000..26562b19948
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/bocsu.h
@@ -0,0 +1,162 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: bocsu.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Author: Markus W. Scherer
+*
+* Modification history:
+* 05/18/2001 weiv Made into separate module
+*/
+
+#ifndef BOCSU_H
+#define BOCSU_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+/*
+ * "BOCSU"
+ * Binary Ordered Compression Scheme for Unicode
+ *
+ * Specific application:
+ *
+ * Encode a Unicode string for the identical level of a sort key.
+ * Restrictions:
+ * - byte stream (unsigned 8-bit bytes)
+ * - lexical order of the identical-level run must be
+ * the same as code point order for the string
+ * - avoid byte values 0, 1, 2
+ *
+ * Method: Slope Detection
+ * Remember the previous code point (initial 0).
+ * For each cp in the string, encode the difference to the previous one.
+ *
+ * With a compact encoding of differences, this yields good results for
+ * small scripts and UTF-like results otherwise.
+ *
+ * Encoding of differences:
+ * - Similar to a UTF, encoding the length of the byte sequence in the lead bytes.
+ * - Does not need to be friendly for decoding or random access
+ * (trail byte values may overlap with lead/single byte values).
+ * - The signedness must be encoded as the most significant part.
+ *
+ * We encode differences with few bytes if their absolute values are small.
+ * For correct ordering, we must treat the entire value range -10ffff..+10ffff
+ * in ascending order, which forbids encoding the sign and the absolute value separately.
+ * Instead, we split the lead byte range in the middle and encode non-negative values
+ * going up and negative values going down.
+ *
+ * For very small absolute values, the difference is added to a middle byte value
+ * for single-byte encoded differences.
+ * For somewhat larger absolute values, the difference is divided by the number
+ * of byte values available, the modulo is used for one trail byte, and the remainder
+ * is added to a lead byte avoiding the single-byte range.
+ * For large absolute values, the difference is similarly encoded in three bytes.
+ *
+ * This encoding does not use byte values 0, 1, 2, but uses all other byte values
+ * for lead/single bytes so that the middle range of single bytes is as large
+ * as possible.
+ * Note that the lead byte ranges overlap some, but that the sequences as a whole
+ * are well ordered. I.e., even if the lead byte is the same for sequences of different
+ * lengths, the trail bytes establish correct order.
+ * It would be possible to encode slightly larger ranges for each length (>1) by
+ * subtracting the lower bound of the range. However, that would also slow down the
+ * calculation.
+ *
+ * For the actual string encoding, an optimization moves the previous code point value
+ * to the middle of its Unicode script block to minimize the differences in
+ * same-script text runs.
+ */
+
+/* Do not use byte values 0, 1, 2 because they are separators in sort keys. */
+#define SLOPE_MIN 3
+#define SLOPE_MAX 0xff
+#define SLOPE_MIDDLE 0x81
+
+#define SLOPE_TAIL_COUNT (SLOPE_MAX-SLOPE_MIN+1)
+
+#define SLOPE_MAX_BYTES 4
+
+/*
+ * Number of lead bytes:
+ * 1 middle byte for 0
+ * 2*80=160 single bytes for !=0
+ * 2*42=84 for double-byte values
+ * 2*3=6 for 3-byte values
+ * 2*1=2 for 4-byte values
+ *
+ * The sum must be <=SLOPE_TAIL_COUNT.
+ *
+ * Why these numbers?
+ * - There should be >=128 single-byte values to cover 128-blocks
+ * with small scripts.
+ * - There should be >=20902 single/double-byte values to cover Unihan.
+ * - It helps CJK Extension B some if there are 3-byte values that cover
+ * the distance between them and Unihan.
+ * This also helps to jump among distant places in the BMP.
+ * - Four-byte values are necessary to cover the rest of Unicode.
+ *
+ * Symmetrical lead byte counts are for convenience.
+ * With an equal distribution of even and odd differences there is also
+ * no advantage to asymmetrical lead byte counts.
+ */
+#define SLOPE_SINGLE 80
+#define SLOPE_LEAD_2 42
+#define SLOPE_LEAD_3 3
+#define SLOPE_LEAD_4 1
+
+/* The difference value range for single-byters. */
+#define SLOPE_REACH_POS_1 SLOPE_SINGLE
+#define SLOPE_REACH_NEG_1 (-SLOPE_SINGLE)
+
+/* The difference value range for double-byters. */
+#define SLOPE_REACH_POS_2 (SLOPE_LEAD_2*SLOPE_TAIL_COUNT+(SLOPE_LEAD_2-1))
+#define SLOPE_REACH_NEG_2 (-SLOPE_REACH_POS_2-1)
+
+/* The difference value range for 3-byters. */
+#define SLOPE_REACH_POS_3 (SLOPE_LEAD_3*SLOPE_TAIL_COUNT*SLOPE_TAIL_COUNT+(SLOPE_LEAD_3-1)*SLOPE_TAIL_COUNT+(SLOPE_TAIL_COUNT-1))
+#define SLOPE_REACH_NEG_3 (-SLOPE_REACH_POS_3-1)
+
+/* The lead byte start values. */
+#define SLOPE_START_POS_2 (SLOPE_MIDDLE+SLOPE_SINGLE+1)
+#define SLOPE_START_POS_3 (SLOPE_START_POS_2+SLOPE_LEAD_2)
+
+#define SLOPE_START_NEG_2 (SLOPE_MIDDLE+SLOPE_REACH_NEG_1)
+#define SLOPE_START_NEG_3 (SLOPE_START_NEG_2-SLOPE_LEAD_2)
+
+/*
+ * Integer division and modulo with negative numerators
+ * yields negative modulo results and quotients that are one more than
+ * what we need here.
+ */
+#define NEGDIVMOD(n, d, m) { \
+ (m)=(n)%(d); \
+ (n)/=(d); \
+ if((m)<0) { \
+ --(n); \
+ (m)+=(d); \
+ } \
+}
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRun(const UChar *s, int32_t length, uint8_t *p);
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRunTwoChars(UChar32 first, UChar32 second, uint8_t *p);
+
+U_CFUNC int32_t
+u_lengthOfIdenticalLevelRun(const UChar *s, int32_t length);
+
+U_CFUNC uint8_t *
+u_writeDiff(int32_t diff, uint8_t *p);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/brktrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/brktrans.cpp
new file mode 100644
index 00000000000..52072667839
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/brktrans.h b/Build/source/libs/icu/icu-4.6/i18n/brktrans.h
new file mode 100644
index 00000000000..00701181d36
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/buddhcal.cpp b/Build/source/libs/icu/icu-4.6/i18n/buddhcal.cpp
new file mode 100644
index 00000000000..92f726c3028
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/buddhcal.h b/Build/source/libs/icu/icu-4.6/i18n/buddhcal.h
new file mode 100644
index 00000000000..735f61890a7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/calendar.cpp b/Build/source/libs/icu/icu-4.6/i18n/calendar.cpp
new file mode 100644
index 00000000000..af2936799eb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/calendar.cpp
@@ -0,0 +1,3374 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
+#endif
+
+// INTERNAL - for cleanup
+
+U_CDECL_BEGIN
+static UBool calendar_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+ if (gService) {
+ delete gService;
+ gService = NULL;
+ }
+#endif
+ return TRUE;
+}
+U_CDECL_END
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+//#define U_DEBUG_CALSVC 1
+//
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+
+/**
+ * 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
+
+static const char * const gCalTypes[] = {
+ "gregorian",
+ "japanese",
+ "buddhist",
+ "roc",
+ "persian",
+ "islamic-civil",
+ "islamic",
+ "hebrew",
+ "chinese",
+ "indian",
+ "coptic",
+ "ethiopic",
+ "ethiopic-amete-alem",
+ 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
+} 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;
+ 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())]));
+ }
+ 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 gDateTimeElements[] = "DateTimeElements";
+static const char gWeekend[] = "weekend";
+
+// 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)
+ }
+ 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;
+ 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 {
+ max <<= 1;
+ if (max < 0) {
+ // Field difference too large to fit into int32_t
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
+ __FILE__, __LINE__, fldName(field));
+#endif
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ }
+ // Do a binary search
+ while ((max - min) > 1 && U_SUCCESS(ec)) {
+ int32_t t = (min + max) / 2;
+ setTimeInMillis(startMs, ec);
+ add(field, t, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return t;
+ } else if (ms > targetMs) {
+ max = t;
+ } else {
+ min = t;
+ }
+ }
+ } else if (startMs > targetMs) {
+ int32_t max = -1;
+ // Find a value that is too small
+ while (U_SUCCESS(ec)) {
+ setTimeInMillis(startMs, ec);
+ add(field, max, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return max;
+ } else if (ms < targetMs) {
+ break;
+ } else {
+ max <<= 1;
+ if (max == 0) {
+ // Field difference too large to fit into int32_t
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
+ __FILE__, __LINE__, fldName(field));
+#endif
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ }
+ // Do a binary search
+ while ((min - max) > 1 && U_SUCCESS(ec)) {
+ int32_t t = (min + max) / 2;
+ setTimeInMillis(startMs, ec);
+ add(field, t, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return t;
+ } else if (ms < targetMs) {
+ max = t;
+ } else {
+ min = t;
+ }
+ }
+ }
+ // Set calendar to end point
+ setTimeInMillis(startMs, ec);
+ add(field, min, ec);
+
+ /* Test for buffer overflows */
+ if(U_FAILURE(ec)) {
+ return 0;
+ }
+ return min;
+}
+
+// -------------------------------------
+
+void
+Calendar::adoptTimeZone(TimeZone* zone)
+{
+ // Do nothing if passed-in zone is NULL
+ if (zone == NULL) return;
+
+ // fZone should always be non-null
+ if (fZone != NULL) delete fZone;
+ fZone = zone;
+
+ // if the zone changes, we need to recompute the time fields
+ fAreFieldsSet = FALSE;
+}
+
+// -------------------------------------
+void
+Calendar::setTimeZone(const TimeZone& zone)
+{
+ adoptTimeZone(zone.clone());
+}
+
+// -------------------------------------
+
+const TimeZone&
+Calendar::getTimeZone() const
+{
+ return *fZone;
+}
+
+// -------------------------------------
+
+TimeZone*
+Calendar::orphanTimeZone()
+{
+ TimeZone *z = fZone;
+ // we let go of the time zone; the new time zone is the system default time zone
+ fZone = TimeZone::createDefault();
+ return z;
+}
+
+// -------------------------------------
+
+void
+Calendar::setLenient(UBool lenient)
+{
+ fLenient = lenient;
+}
+
+// -------------------------------------
+
+UBool
+Calendar::isLenient() const
+{
+ return fLenient;
+}
+
+// -------------------------------------
+
+void
+Calendar::setFirstDayOfWeek(UCalendarDaysOfWeek value)
+{
+ if (fFirstDayOfWeek != value &&
+ value >= UCAL_SUNDAY && value <= UCAL_SATURDAY) {
+ fFirstDayOfWeek = value;
+ fAreFieldsSet = FALSE;
+ }
+}
+
+// -------------------------------------
+
+Calendar::EDaysOfWeek
+Calendar::getFirstDayOfWeek() const
+{
+ return (Calendar::EDaysOfWeek)fFirstDayOfWeek;
+}
+
+UCalendarDaysOfWeek
+Calendar::getFirstDayOfWeek(UErrorCode & /*status*/) const
+{
+ return fFirstDayOfWeek;
+}
+// -------------------------------------
+
+void
+Calendar::setMinimalDaysInFirstWeek(uint8_t value)
+{
+ // Values less than 1 have the same effect as 1; values greater
+ // than 7 have the same effect as 7. However, we normalize values
+ // so operator== and so forth work.
+ if (value < 1) {
+ value = 1;
+ } else if (value > 7) {
+ value = 7;
+ }
+ if (fMinimalDaysInFirstWeek != value) {
+ fMinimalDaysInFirstWeek = value;
+ fAreFieldsSet = FALSE;
+ }
+}
+
+// -------------------------------------
+
+uint8_t
+Calendar::getMinimalDaysInFirstWeek() const
+{
+ return fMinimalDaysInFirstWeek;
+}
+
+// -------------------------------------
+// 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 (isSet((UCalendarDateFields)field)) {
+ validateField((UCalendarDateFields)field, status);
+ }
+ }
+}
+
+/**
+* Validate a single field of this calendar. Subclasses should
+* override this method to validate any calendar-specific fields.
+* Generic fields can be handled by
+* <code>Calendar.validateField()</code>.
+* @see #validateField(int, int, int)
+*/
+void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
+ int32_t y;
+ switch (field) {
+ case UCAL_DAY_OF_MONTH:
+ y = handleGetExtendedYear();
+ validateField(field, 1, handleGetMonthLength(y, internalGet(UCAL_MONTH)), status);
+ break;
+ case UCAL_DAY_OF_YEAR:
+ y = handleGetExtendedYear();
+ validateField(field, 1, handleGetYearLength(y), status);
+ break;
+ case UCAL_DAY_OF_WEEK_IN_MONTH:
+ if (internalGet(field) == 0) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because DOW in month cannot be 0\n",
+ __FILE__, __LINE__);
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR; // "DAY_OF_WEEK_IN_MONTH cannot be zero"
+ return;
+ }
+ validateField(field, getMinimum(field), getMaximum(field), status);
+ break;
+ default:
+ validateField(field, getMinimum(field), getMaximum(field), status);
+ break;
+ }
+}
+
+/**
+* Validate a single field of this calendar given its minimum and
+* maximum allowed value. If the field is out of range, throw a
+* descriptive <code>IllegalArgumentException</code>. Subclasses may
+* use this method in their implementation of {@link
+* #validateField(int)}.
+*/
+void Calendar::validateField(UCalendarDateFields field, int32_t min, int32_t max, UErrorCode& status)
+{
+ int32_t value = fFields[field];
+ if (value < min || value > max) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because of field %s out of range %d..%d at %d\n",
+ __FILE__, __LINE__,fldName(field),min,max,value);
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+}
+
+// -------------------------
+
+const UFieldResolutionTable* Calendar::getFieldResolutionTable() const {
+ return kDatePrecedence;
+}
+
+
+UCalendarDateFields Calendar::newerField(UCalendarDateFields defaultField, UCalendarDateFields alternateField) const
+{
+ if (fStamp[alternateField] > fStamp[defaultField]) {
+ return alternateField;
+ }
+ return defaultField;
+}
+
+UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) {
+ int32_t bestField = UCAL_FIELD_COUNT;
+ for (int32_t g=0; precedenceTable[g][0][0] != -1 && (bestField == UCAL_FIELD_COUNT); ++g) {
+ int32_t bestStamp = kUnset;
+ for (int32_t l=0; precedenceTable[g][l][0] != -1; ++l) {
+ int32_t lineStamp = kUnset;
+ // Skip over first entry if it is negative
+ for (int32_t i=((precedenceTable[g][l][0]>=kResolveRemap)?1:0); precedenceTable[g][l][i]!=-1; ++i) {
+ int32_t s = fStamp[precedenceTable[g][l][i]];
+ // If any field is unset then don't use this line
+ if (s == kUnset) {
+ goto linesInGroup;
+ } else if(s > lineStamp) {
+ lineStamp = s;
+ }
+ }
+ // Record new maximum stamp & field no.
+ if (lineStamp > bestStamp) {
+ bestStamp = lineStamp;
+ bestField = precedenceTable[g][l][0]; // First field refers to entire line
+ }
+linesInGroup:
+ ;
+ }
+ }
+ return (UCalendarDateFields)( (bestField>=kResolveRemap)?(bestField&(kResolveRemap-1)):bestField );
+}
+
+const UFieldResolutionTable Calendar::kDatePrecedence[] =
+{
+ {
+ { UCAL_DAY_OF_MONTH, kResolveSTOP },
+ { UCAL_WEEK_OF_YEAR, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { UCAL_WEEK_OF_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { UCAL_WEEK_OF_YEAR, UCAL_DOW_LOCAL, kResolveSTOP },
+ { UCAL_WEEK_OF_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
+ { UCAL_DAY_OF_YEAR, kResolveSTOP },
+ { kResolveRemap | UCAL_DAY_OF_MONTH, UCAL_YEAR, kResolveSTOP }, // if YEAR is set over YEAR_WOY use DAY_OF_MONTH
+ { kResolveRemap | UCAL_WEEK_OF_YEAR, UCAL_YEAR_WOY, kResolveSTOP }, // if YEAR_WOY is set, calc based on WEEK_OF_YEAR
+ { kResolveSTOP }
+ },
+ {
+ { UCAL_WEEK_OF_YEAR, kResolveSTOP },
+ { UCAL_WEEK_OF_MONTH, kResolveSTOP },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, kResolveSTOP },
+ { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
+ { kResolveSTOP }
+ },
+ {{kResolveSTOP}}
+};
+
+
+const UFieldResolutionTable Calendar::kDOWPrecedence[] =
+{
+ {
+ { UCAL_DAY_OF_WEEK,kResolveSTOP, kResolveSTOP },
+ { UCAL_DOW_LOCAL,kResolveSTOP, kResolveSTOP },
+ {kResolveSTOP}
+ },
+ {{kResolveSTOP}}
+};
+
+// precedence for calculating a year
+const UFieldResolutionTable Calendar::kYearPrecedence[] =
+{
+ {
+ { UCAL_YEAR, kResolveSTOP },
+ { UCAL_EXTENDED_YEAR, kResolveSTOP },
+ { UCAL_YEAR_WOY, UCAL_WEEK_OF_YEAR, kResolveSTOP }, // YEAR_WOY is useless without WEEK_OF_YEAR
+ { kResolveSTOP }
+ },
+ {{kResolveSTOP}}
+};
+
+
+// -------------------------
+
+
+void Calendar::computeTime(UErrorCode& status) {
+ if (!isLenient()) {
+ validateFields(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ // Compute the Julian day
+ int32_t julianDay = computeJulianDay();
+
+ double millis = Grego::julianDayToMillis(julianDay);
+
+#if defined (U_DEBUG_CAL)
+ // int32_t julianInsanityCheck = (int32_t)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->prepareGetActual(field,FALSE,status);
+ result = handleGetMonthLength(cal->get(UCAL_EXTENDED_YEAR, status), cal->get(UCAL_MONTH, status));
+ delete cal;
+ }
+ break;
+
+ case UCAL_DAY_OF_YEAR:
+ {
+ if(U_FAILURE(status)) return 0;
+ Calendar *cal = clone();
+ if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
+ cal->prepareGetActual(field,FALSE,status);
+ result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status));
+ delete cal;
+ }
+ break;
+
+ case UCAL_DAY_OF_WEEK:
+ case UCAL_AM_PM:
+ case UCAL_HOUR:
+ case UCAL_HOUR_OF_DAY:
+ case UCAL_MINUTE:
+ case UCAL_SECOND:
+ case UCAL_MILLISECOND:
+ case UCAL_ZONE_OFFSET:
+ case UCAL_DST_OFFSET:
+ case UCAL_DOW_LOCAL:
+ case UCAL_JULIAN_DAY:
+ case UCAL_MILLISECONDS_IN_DAY:
+ // These fields all have fixed minima/maxima
+ result = getMaximum(field);
+ break;
+
+ default:
+ // For all other fields, do it the hard way....
+ result = getActualHelper(field, getLeastMaximum(field), getMaximum(field),status);
+ break;
+ }
+ return result;
+}
+
+
+/**
+* Prepare this calendar for computing the actual minimum or maximum.
+* This method modifies this calendar's fields; it is called on a
+* temporary calendar.
+*
+* <p>Rationale: The semantics of getActualXxx() is to return the
+* maximum or minimum value that the given field can take, taking into
+* account other relevant fields. In general these other fields are
+* larger fields. For example, when computing the actual maximum
+* DATE, the current value of DATE itself is ignored,
+* as is the value of any field smaller.
+*
+* <p>The time fields all have fixed minima and maxima, so we don't
+* need to worry about them. This also lets us set the
+* MILLISECONDS_IN_DAY to zero to erase any effects the time fields
+* might have when computing date fields.
+*
+* <p>DAY_OF_WEEK is adjusted specially for the WEEK_OF_MONTH and
+* WEEK_OF_YEAR fields to ensure that they are computed correctly.
+* @internal
+*/
+void Calendar::prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErrorCode &status)
+{
+ set(UCAL_MILLISECONDS_IN_DAY, 0);
+
+ switch (field) {
+ case UCAL_YEAR:
+ case UCAL_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; }
+ 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)
+{
+ // Read the week count data from the resource bundle. This should
+ // have the form:
+ //
+ // DateTimeElements:intvector {
+ // 1, // first day of week
+ // 1 // min days in week
+ // }
+ // Both have a range of 1..7
+
+
+ if (U_FAILURE(status)) return;
+
+ fFirstDayOfWeek = UCAL_SUNDAY;
+ fMinimalDaysInFirstWeek = 1;
+ 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);
+ }
+
+ CalendarData calData(useLocale, type, status);
+ // If the resource data doesn't seem to be present at all, then use last-resort
+ // hard-coded data.
+ UResourceBundle *dateTimeElements = calData.getByKey(gDateTimeElements, status);
+
+ if (U_FAILURE(status)) {
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, " Failure loading dateTimeElements = %s\n", u_errorName(status));
+#endif
+ status = U_USING_FALLBACK_WARNING;
+ } else {
+ U_LOCALE_BASED(locBased, *this);
+ locBased.setLocaleIDs(ures_getLocaleByType(dateTimeElements, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(dateTimeElements, ULOC_ACTUAL_LOCALE, &status));
+ if (U_SUCCESS(status)) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, " Valid=%s, Actual=%s\n", validLocale, actualLocale);
+#endif
+ int32_t arrLen;
+ const int32_t *dateTimeElementsArr = ures_getIntVector(dateTimeElements, &arrLen, &status);
+
+ if(U_SUCCESS(status) && arrLen == 2
+ && 1 <= dateTimeElementsArr[0] && dateTimeElementsArr[0] <= 7
+ && 1 <= dateTimeElementsArr[1] && dateTimeElementsArr[1] <= 7)
+ {
+ fFirstDayOfWeek = (UCalendarDaysOfWeek)dateTimeElementsArr[0];
+ fMinimalDaysInFirstWeek = (uint8_t)dateTimeElementsArr[1];
+ }
+ else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ }
+ // do NOT close dateTimeElements
+
+ if (U_SUCCESS(status)) {
+ UResourceBundle *weekend = calData.getByKey(gWeekend, status);
+ if (U_FAILURE(status)) {
+ status = U_USING_FALLBACK_WARNING;
+ } else {
+ int32_t arrLen;
+ const int32_t *weekendArr = ures_getIntVector(weekend, &arrLen, &status);
+ if(U_SUCCESS(status) && arrLen >= 4
+ && 1 <= weekendArr[0] && weekendArr[0] <= 7
+ && 1 <= weekendArr[2] && weekendArr[2] <= 7)
+ {
+ fWeekendOnset = (UCalendarDaysOfWeek)weekendArr[0];
+ fWeekendOnsetMillis = weekendArr[1];
+ fWeekendCease = (UCalendarDaysOfWeek)weekendArr[2];
+ fWeekendCeaseMillis = weekendArr[3];
+ }
+ else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ }
+}
+
+/**
+* Recompute the time and update the status fields isTimeSet
+* and areFieldsSet. Callers should check isTimeSet and only
+* call this method if isTimeSet is false.
+*/
+void
+Calendar::updateTime(UErrorCode& status)
+{
+ computeTime(status);
+ if(U_FAILURE(status))
+ return;
+
+ // If we are lenient, we need to recompute the fields to normalize
+ // the values. Also, if we haven't set all the fields yet (i.e.,
+ // in a newly-created object), we need to fill in the fields. [LIU]
+ if (isLenient() || ! fAreAllFieldsSet)
+ fAreFieldsSet = FALSE;
+
+ fIsTimeSet = TRUE;
+ fAreFieldsVirtuallySet = FALSE;
+}
+
+Locale
+Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocale(type, status);
+}
+
+const char *
+Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocaleID(type, status);
+}
+
+// Deprecated function. This doesn't need to be inline.
+void
+Calendar::internalSet(EDateFields field, int32_t value)
+{
+ internalSet((UCalendarDateFields) field, value);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/casetrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/casetrn.cpp
new file mode 100644
index 00000000000..5038c51da3d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/casetrn.h b/Build/source/libs/icu/icu-4.6/i18n/casetrn.h
new file mode 100644
index 00000000000..48233ccc3dc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/cecal.cpp b/Build/source/libs/icu/icu-4.6/i18n/cecal.cpp
new file mode 100644
index 00000000000..ab4eca97ef1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/cecal.h b/Build/source/libs/icu/icu-4.6/i18n/cecal.h
new file mode 100644
index 00000000000..471d88933e8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/chnsecal.cpp b/Build/source/libs/icu/icu-4.6/i18n/chnsecal.cpp
new file mode 100644
index 00000000000..0f22812bde4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/chnsecal.h b/Build/source/libs/icu/icu-4.6/i18n/chnsecal.h
new file mode 100644
index 00000000000..d379770e174
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/choicfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/choicfmt.cpp
new file mode 100644
index 00000000000..ae5387273e3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/choicfmt.cpp
@@ -0,0 +1,764 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2009, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File CHOICFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation and got rid
+* of nextDouble/previousDouble and replaced with
+* boolean array.
+* 4/10/97 aliu Clean up. Modified to work on AIX.
+* 06/04/97 helena Fixed applyPattern(), toPattern() and not to include
+* wchar.h.
+* 07/09/97 helena Made ParsePosition into a class.
+* 08/06/97 nos removed overloaded constructor, fixed 'format(array)'
+* 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags)
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/choicfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "cpputils.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include <stdio.h>
+#include <float.h>
+
+// *****************************************************************************
+// class ChoiceFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
+
+// Special characters used by ChoiceFormat. There are two characters
+// used interchangeably to indicate <=. Either is parsed, but only
+// LESS_EQUAL is generated by toPattern().
+#define SINGLE_QUOTE ((UChar)0x0027) /*'*/
+#define LESS_THAN ((UChar)0x003C) /*<*/
+#define LESS_EQUAL ((UChar)0x0023) /*#*/
+#define LESS_EQUAL2 ((UChar)0x2264)
+#define VERTICAL_BAR ((UChar)0x007C) /*|*/
+#define MINUS ((UChar)0x002D) /*-*/
+
+#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)
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ applyPattern(newPattern, status);
+}
+
+// -------------------------------------
+// Creates a ChoiceFormat instance with the limit array and
+// format strings for each limit.
+
+ChoiceFormat::ChoiceFormat(const double* limits,
+ const UnicodeString* formats,
+ int32_t cnt )
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ setChoices(limits, formats, cnt );
+}
+
+// -------------------------------------
+
+ChoiceFormat::ChoiceFormat(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t cnt )
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ setChoices(limits, closures, formats, cnt );
+}
+
+// -------------------------------------
+// copy constructor
+
+ChoiceFormat::ChoiceFormat(const ChoiceFormat& that)
+: NumberFormat(that),
+ fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0)
+{
+ *this = that;
+}
+
+// -------------------------------------
+// Private constructor that creates a
+// ChoiceFormat instance based on the
+// pattern and populates UParseError
+
+ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
+ UParseError& parseError,
+ UErrorCode& status)
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ applyPattern(newPattern,parseError, status);
+}
+// -------------------------------------
+
+UBool
+ChoiceFormat::operator==(const Format& that) const
+{
+ if (this == &that) return TRUE;
+ if (!NumberFormat::operator==(that)) return FALSE;
+ ChoiceFormat& thatAlias = (ChoiceFormat&)that;
+ if (fCount != thatAlias.fCount) return FALSE;
+ // Checks the limits, the corresponding format string and LE or LT flags.
+ // LE means less than and equal to, LT means less than.
+ for (int32_t i = 0; i < fCount; i++) {
+ if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) ||
+ (fClosures[i] != thatAlias.fClosures[i]) ||
+ (fChoiceFormats[i] != thatAlias.fChoiceFormats[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// -------------------------------------
+// copy constructor
+
+const ChoiceFormat&
+ChoiceFormat::operator=(const ChoiceFormat& that)
+{
+ if (this != &that) {
+ NumberFormat::operator=(that);
+ fCount = that.fCount;
+ uprv_free(fChoiceLimits);
+ fChoiceLimits = NULL;
+ uprv_free(fClosures);
+ fClosures = NULL;
+ delete [] fChoiceFormats;
+ fChoiceFormats = NULL;
+
+ fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
+ fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
+ fChoiceFormats = new UnicodeString[fCount];
+
+ // check for memory allocation error
+ if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
+ if (fChoiceLimits) {
+ uprv_free(fChoiceLimits);
+ fChoiceLimits = NULL;
+ }
+ if (fClosures) {
+ uprv_free(fClosures);
+ fClosures = NULL;
+ }
+ if (fChoiceFormats) {
+ delete[] fChoiceFormats;
+ fChoiceFormats = NULL;
+ }
+ } else {
+ uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount);
+ uprv_arrayCopy(that.fClosures, fClosures, fCount);
+ uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount);
+ }
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+ChoiceFormat::~ChoiceFormat()
+{
+ uprv_free(fChoiceLimits);
+ fChoiceLimits = NULL;
+ uprv_free(fClosures);
+ fClosures = NULL;
+ delete [] fChoiceFormats;
+ fChoiceFormats = NULL;
+ fCount = 0;
+}
+
+/**
+ * Convert a string to a double value
+ */
+double
+ChoiceFormat::stod(const UnicodeString& string)
+{
+ char source[256];
+ char* end;
+
+ string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV); /* invariant codepage */
+ return uprv_strtod(source,&end);
+}
+
+// -------------------------------------
+
+/**
+ * Convert a double value to a string without the overhead of ICU.
+ */
+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)
+{
+ UParseError parseError;
+ applyPattern(pattern, parseError, status);
+}
+
+// -------------------------------------
+// Applies the pattern to this ChoiceFormat instance.
+
+void
+ChoiceFormat::applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status))
+ {
+ return;
+ }
+
+ // Clear error struct
+ parseError.offset = -1;
+ parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
+
+ // Perform 2 passes. The first computes the number of limits in
+ // this pattern (fCount), which is 1 more than the number of
+ // literal VERTICAL_BAR characters.
+ int32_t count = 1;
+ int32_t i;
+ for (i=0; i<pattern.length(); ++i) {
+ UChar c = pattern[i];
+ if (c == SINGLE_QUOTE) {
+ // Skip over the entire quote, including embedded
+ // contiguous pairs of SINGLE_QUOTE.
+ for (;;) {
+ do {
+ ++i;
+ } while (i<pattern.length() &&
+ pattern[i] != SINGLE_QUOTE);
+ if ((i+1)<pattern.length() &&
+ pattern[i+1] == SINGLE_QUOTE) {
+ // SINGLE_QUOTE pair; skip over it
+ ++i;
+ } else {
+ break;
+ }
+ }
+ } else if (c == VERTICAL_BAR) {
+ ++count;
+ }
+ }
+
+ // Allocate the required storage.
+ double *newLimits = (double*) uprv_malloc( sizeof(double) * count);
+ /* test for NULL */
+ if (newLimits == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count);
+ /* test for NULL */
+ if (newClosures == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(newLimits);
+ return;
+ }
+ UnicodeString *newFormats = new UnicodeString[count];
+ /* test for NULL */
+ if (newFormats == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(newLimits);
+ uprv_free(newClosures);
+ return;
+ }
+
+ // Perform the second pass
+ int32_t k = 0; // index into newXxx[] arrays
+ UnicodeString buf; // scratch buffer
+ UBool inQuote = FALSE;
+ UBool inNumber = TRUE; // TRUE before < or #, FALSE after
+
+ for (i=0; i<pattern.length(); ++i) {
+ UChar c = pattern[i];
+ if (c == SINGLE_QUOTE) {
+ // Check for SINGLE_QUOTE pair indicating a literal quote
+ if ((i+1) < pattern.length() &&
+ pattern[i+1] == SINGLE_QUOTE) {
+ buf += SINGLE_QUOTE;
+ ++i;
+ } else {
+ inQuote = !inQuote;
+ }
+ } else if (inQuote) {
+ buf += c;
+ } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) {
+ if (!inNumber || buf.length() == 0) {
+ goto error;
+ }
+ inNumber = FALSE;
+
+ double limit;
+ buf.trim();
+ if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) {
+ limit = uprv_getInfinity();
+ } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) {
+ limit = -uprv_getInfinity();
+ } else {
+ limit = stod(buf);
+ }
+
+ if (k == count) {
+ // This shouldn't happen. If it does, it means that
+ // the count determined in the first pass did not
+ // match the number of elements found in the second
+ // pass.
+ goto error;
+ }
+ newLimits[k] = limit;
+ newClosures[k] = (c == LESS_THAN);
+
+ if (k > 0 && limit <= newLimits[k-1]) {
+ // Each limit must be strictly > than the previous
+ // limit. One exception: Two subsequent limits may be
+ // == if the first closure is FALSE and the second
+ // closure is TRUE. This places the limit value in
+ // the second interval.
+ if (!(limit == newLimits[k-1] &&
+ !newClosures[k-1] &&
+ newClosures[k])) {
+ goto error;
+ }
+ }
+
+ buf.truncate(0);
+ } else if (c == VERTICAL_BAR) {
+ if (inNumber) {
+ goto error;
+ }
+ inNumber = TRUE;
+
+ newFormats[k] = buf;
+ ++k;
+ buf.truncate(0);
+ } else {
+ buf += c;
+ }
+ }
+
+ if (k != (count-1) || inNumber || inQuote) {
+ goto error;
+ }
+ newFormats[k] = buf;
+
+ // Don't modify this object until the parse succeeds
+ uprv_free(fChoiceLimits);
+ uprv_free(fClosures);
+ delete[] fChoiceFormats;
+ fCount = count;
+ fChoiceLimits = newLimits;
+ fClosures = newClosures;
+ fChoiceFormats = newFormats;
+ return;
+
+error:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ syntaxError(pattern,i,parseError);
+ uprv_free(newLimits);
+ uprv_free(newClosures);
+ delete[] newFormats;
+ return;
+
+}
+// -------------------------------------
+// Reconstruct the original input pattern.
+
+UnicodeString&
+ChoiceFormat::toPattern(UnicodeString& result) const
+{
+ result.remove();
+ for (int32_t i = 0; i < fCount; ++i) {
+ if (i != 0) {
+ result += VERTICAL_BAR;
+ }
+ UnicodeString buf;
+ if (uprv_isPositiveInfinity(fChoiceLimits[i])) {
+ result += INFINITY;
+ } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) {
+ result += MINUS;
+ result += INFINITY;
+ } else {
+ result += dtos(fChoiceLimits[i], buf);
+ }
+ if (fClosures[i]) {
+ result += LESS_THAN;
+ } else {
+ result += LESS_EQUAL;
+ }
+ // Append fChoiceFormats[i], using quotes if there are special
+ // characters. Single quotes themselves must be escaped in
+ // either case.
+ const UnicodeString& text = fChoiceFormats[i];
+ UBool needQuote = text.indexOf(LESS_THAN) >= 0
+ || text.indexOf(LESS_EQUAL) >= 0
+ || text.indexOf(LESS_EQUAL2) >= 0
+ || text.indexOf(VERTICAL_BAR) >= 0;
+ if (needQuote) {
+ result += SINGLE_QUOTE;
+ }
+ if (text.indexOf(SINGLE_QUOTE) < 0) {
+ result += text;
+ }
+ else {
+ for (int32_t j = 0; j < text.length(); ++j) {
+ UChar c = text[j];
+ result += c;
+ if (c == SINGLE_QUOTE) {
+ result += c;
+ }
+ }
+ }
+ if (needQuote) {
+ result += SINGLE_QUOTE;
+ }
+ }
+
+ return result;
+}
+
+// -------------------------------------
+// Sets the limit and format arrays.
+void
+ChoiceFormat::setChoices( const double* limits,
+ const UnicodeString* formats,
+ int32_t cnt )
+{
+ setChoices(limits, 0, formats, cnt);
+}
+
+// -------------------------------------
+// Sets the limit and format arrays.
+void
+ChoiceFormat::setChoices( const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t cnt )
+{
+ if(limits == 0 || formats == 0)
+ return;
+
+ if (fChoiceLimits) {
+ uprv_free(fChoiceLimits);
+ }
+ if (fClosures) {
+ uprv_free(fClosures);
+ }
+ if (fChoiceFormats) {
+ delete [] fChoiceFormats;
+ }
+
+ // Note that the old arrays are deleted and this owns
+ // the created array.
+ fCount = cnt;
+ fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
+ fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
+ fChoiceFormats = new UnicodeString[fCount];
+
+ //check for memory allocation error
+ if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
+ if (fChoiceLimits) {
+ uprv_free(fChoiceLimits);
+ fChoiceLimits = NULL;
+ }
+ if (fClosures) {
+ uprv_free(fClosures);
+ fClosures = NULL;
+ }
+ if (fChoiceFormats) {
+ delete[] fChoiceFormats;
+ fChoiceFormats = NULL;
+ }
+ return;
+ }
+
+ uprv_arrayCopy(limits, fChoiceLimits, fCount);
+ uprv_arrayCopy(formats, fChoiceFormats, fCount);
+
+ if (closures != 0) {
+ uprv_arrayCopy(closures, fClosures, fCount);
+ } else {
+ int32_t i;
+ for (i=0; i<fCount; ++i) {
+ fClosures[i] = FALSE;
+ }
+ }
+}
+
+// -------------------------------------
+// Gets the limit array.
+
+const double*
+ChoiceFormat::getLimits(int32_t& cnt) const
+{
+ cnt = fCount;
+ return fChoiceLimits;
+}
+
+// -------------------------------------
+// Gets the closures array.
+
+const UBool*
+ChoiceFormat::getClosures(int32_t& cnt) const
+{
+ cnt = fCount;
+ return fClosures;
+}
+
+// -------------------------------------
+// Gets the format array.
+
+const UnicodeString*
+ChoiceFormat::getFormats(int32_t& cnt) const
+{
+ cnt = fCount;
+ return fChoiceFormats;
+}
+
+// -------------------------------------
+// Formats an int64 number, it's actually formatted as
+// a double. The returned format string may differ
+// from the input number because of this.
+
+UnicodeString&
+ChoiceFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& status) const
+{
+ return format((double) number, appendTo, status);
+}
+
+// -------------------------------------
+// Formats a long number, it's actually formatted as
+// a double. The returned format string may differ
+// from the input number because of this.
+
+UnicodeString&
+ChoiceFormat::format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& status) const
+{
+ return format((double) number, appendTo, status);
+}
+
+// -------------------------------------
+// Formats a double number.
+
+UnicodeString&
+ChoiceFormat::format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& /*pos*/) const
+{
+ // find the number
+ int32_t i;
+ for (i = 0; i < fCount; ++i) {
+ if (fClosures[i]) {
+ if (!(number > fChoiceLimits[i])) {
+ // same as number <= fChoiceLimits, except catches NaN
+ break;
+ }
+ } else if (!(number >= fChoiceLimits[i])) {
+ // same as number < fChoiceLimits, except catches NaN
+ break;
+ }
+ }
+ --i;
+ if (i < 0) {
+ i = 0;
+ }
+ // return either a formatted number, or a string
+ appendTo += fChoiceFormats[i];
+ return appendTo;
+}
+
+// -------------------------------------
+// Formats an array of objects. Checks if the data type of the objects
+// to get the right value for formatting.
+
+UnicodeString&
+ChoiceFormat::format(const Formattable* objs,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if(cnt < 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ UnicodeString buffer;
+ for (int32_t i = 0; i < cnt; i++) {
+ double objDouble = objs[i].getDouble(status);
+ if (U_SUCCESS(status)) {
+ buffer.remove();
+ appendTo += format(objDouble, buffer, pos);
+ }
+ }
+
+ return appendTo;
+}
+
+// -------------------------------------
+// Formats an array of objects. Checks if the data type of the objects
+// to get the right value for formatting.
+
+UnicodeString&
+ChoiceFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ return NumberFormat::format(obj, appendTo, pos, status);
+}
+// -------------------------------------
+
+void
+ChoiceFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& status) const
+{
+ // find the best number (defined as the one with the longest parse)
+ int32_t start = status.getIndex();
+ int32_t furthest = start;
+ double bestNumber = uprv_getNaN();
+ double tempNumber = 0.0;
+ for (int i = 0; i < fCount; ++i) {
+ int32_t len = fChoiceFormats[i].length();
+ if (text.compare(start, len, fChoiceFormats[i]) == 0) {
+ status.setIndex(start + len);
+ tempNumber = fChoiceLimits[i];
+ if (status.getIndex() > furthest) {
+ furthest = status.getIndex();
+ bestNumber = tempNumber;
+ if (furthest == text.length())
+ break;
+ }
+ }
+ }
+ status.setIndex(furthest);
+ if (status.getIndex() == start) {
+ status.setErrorIndex(furthest);
+ }
+ result.setDouble(bestNumber);
+}
+
+// -------------------------------------
+// Parses the text and return the Formattable object.
+
+void
+ChoiceFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const
+{
+ NumberFormat::parse(text, result, status);
+}
+
+// -------------------------------------
+
+Format*
+ChoiceFormat::clone() const
+{
+ ChoiceFormat *aCopy = new ChoiceFormat(*this);
+ return aCopy;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/coleitr.cpp b/Build/source/libs/icu/icu-4.6/i18n/coleitr.cpp
new file mode 100644
index 00000000000..173166af622
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/coll.cpp b/Build/source/libs/icu/icu-4.6/i18n/coll.cpp
new file mode 100644
index 00000000000..83c7565af00
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/coll.cpp
@@ -0,0 +1,866 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2010, 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 Collator::getReorderCodes(int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode& status) const
+{
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return 0;
+}
+
+void Collator::setReorderCodes(const int32_t *reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+}
+
+// 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.6/i18n/colldata.cpp b/Build/source/libs/icu/icu-4.6/i18n/colldata.cpp
new file mode 100644
index 00000000000..c5349d2b60b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/colldata.cpp
@@ -0,0 +1,1100 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2009, 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];
+
+ uprv_memcpy(newStrings, strings, listSize * sizeof(UnicodeString));
+
+#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);
+
+ UMTX lock;
+ UHashtable *cache;
+};
+
+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)
+ : lock(0), 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);
+
+ umtx_destroy(&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.6/i18n/coptccal.cpp b/Build/source/libs/icu/icu-4.6/i18n/coptccal.cpp
new file mode 100644
index 00000000000..84bbad797ea
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/coptccal.h b/Build/source/libs/icu/icu-4.6/i18n/coptccal.h
new file mode 100644
index 00000000000..f42230dff4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/cpdtrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/cpdtrans.cpp
new file mode 100644
index 00000000000..ebe5d44bf6c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/cpdtrans.h b/Build/source/libs/icu/icu-4.6/i18n/cpdtrans.h
new file mode 100644
index 00000000000..e964d4cc3af
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/cpdtrans.h
@@ -0,0 +1,248 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2009, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef CPDTRANS_H
+#define CPDTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+class U_COMMON_API UVector;
+class TransliteratorRegistry;
+
+/**
+ * A transliterator that is composed of two or more other
+ * transliterator objects linked together. For example, if one
+ * transliterator transliterates from script A to script B, and
+ * another transliterates from script B to script C, the two may be
+ * combined to form a new transliterator from A to C.
+ *
+ * <p>Composed transliterators may not behave as expected. For
+ * example, inverses may not combine to form the identity
+ * transliterator. See the class documentation for {@link
+ * Transliterator} for details.
+ *
+ * @author Alan Liu
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+class U_I18N_API CompoundTransliterator : public Transliterator {
+
+ Transliterator** trans;
+
+ int32_t count;
+
+ int32_t numAnonymousRBTs;
+
+public:
+
+ /**
+ * Constructs a new compound transliterator given an array of
+ * transliterators. The array of transliterators may be of any
+ * length, including zero or one, however, useful compound
+ * transliterators have at least two components.
+ * @param transliterators array of <code>Transliterator</code>
+ * objects
+ * @param transliteratorCount The number of
+ * <code>Transliterator</code> objects in transliterators.
+ * @param adoptedFilter the filter. Any character for which
+ * <tt>filter.contains()</tt> returns <tt>false</tt> will not be
+ * altered by this transliterator. If <tt>filter</tt> is
+ * <tt>null</tt> then no filtering is applied.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(Transliterator* const transliterators[],
+ int32_t transliteratorCount,
+ UnicodeFilter* adoptedFilter = 0);
+
+ /**
+ * Constructs a new compound transliterator.
+ * @param id compound ID
+ * @param dir either UTRANS_FORWARD or UTRANS_REVERSE
+ * @param adoptedFilter a global filter for this compound transliterator
+ * or NULL
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(const UnicodeString& id,
+ UTransDirection dir,
+ UnicodeFilter* adoptedFilter,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Constructs a new compound transliterator in the FORWARD
+ * direction with a NULL filter.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(const UnicodeString& id,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Destructor.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual ~CompoundTransliterator();
+
+ /**
+ * Copy constructor.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(const CompoundTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * Returns the number of transliterators in this chain.
+ * @return number of transliterators in this chain.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual int32_t getCount(void) const;
+
+ /**
+ * Returns the transliterator at the given index in this chain.
+ * @param idx index into chain, from 0 to <code>getCount() - 1</code>
+ * @return transliterator at the given index
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual const Transliterator& getTransliterator(int32_t idx) const;
+
+ /**
+ * Sets the transliterators.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ void setTransliterators(Transliterator* const transliterators[],
+ int32_t count);
+
+ /**
+ * Adopts the transliterators.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ void adoptTransliterators(Transliterator* adoptedTransliterators[],
+ int32_t count);
+
+ /**
+ * Override Transliterator:
+ * Create a rule string that can be passed to createFromRules()
+ * to recreate this transliterator.
+ * @param result the string to receive the rules. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \uxxxx or
+ * \Uxxxxxxxx. Unprintable characters are those other than
+ * U+000A, U+0020..U+007E.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual UnicodeString& toRules(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ protected:
+ /**
+ * Implement Transliterator framework
+ */
+ virtual void handleGetSourceSet(UnicodeSet& result) const;
+
+ public:
+ /**
+ * Override Transliterator framework
+ */
+ virtual UnicodeSet& getTargetSet(UnicodeSet& result) const;
+
+protected:
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& idx,
+ UBool incremental) const;
+
+public:
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /* @internal */
+ static const UChar PASS_STRING[];
+
+private:
+
+ friend class Transliterator;
+ friend class TransliteratorAlias; // to access private ct
+
+ /**
+ * Assignment operator.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator& operator=(const CompoundTransliterator&);
+
+ /**
+ * Private constructor for Transliterator.
+ */
+ CompoundTransliterator(const UnicodeString& ID,
+ UVector& list,
+ UnicodeFilter* adoptedFilter,
+ int32_t numAnonymousRBTs,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ CompoundTransliterator(UVector& list,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ CompoundTransliterator(UVector& list,
+ int32_t anonymousRBTs,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ void init(const UnicodeString& id,
+ UTransDirection direction,
+ UBool fixReverseID,
+ UErrorCode& status);
+
+ void init(UVector& list,
+ UTransDirection direction,
+ UBool fixReverseID,
+ UErrorCode& status);
+
+ /**
+ * Return the IDs of the given list of transliterators, concatenated
+ * with ';' delimiting them. Equivalent to the perlish expression
+ * join(';', map($_.getID(), transliterators).
+ */
+ UnicodeString joinIDs(Transliterator* const transliterators[],
+ int32_t transCount);
+
+ void freeTransliterators(void);
+
+ void computeMaximumContextLength(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/csdetect.cpp b/Build/source/libs/icu/icu-4.6/i18n/csdetect.cpp
new file mode 100644
index 00000000000..26c0f6c323c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csdetect.h b/Build/source/libs/icu/icu-4.6/i18n/csdetect.h
new file mode 100644
index 00000000000..405e1f55800
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csmatch.cpp b/Build/source/libs/icu/icu-4.6/i18n/csmatch.cpp
new file mode 100644
index 00000000000..f1d25d2dde9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csmatch.h b/Build/source/libs/icu/icu-4.6/i18n/csmatch.h
new file mode 100644
index 00000000000..50b78a3a1dc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csr2022.cpp b/Build/source/libs/icu/icu-4.6/i18n/csr2022.cpp
new file mode 100644
index 00000000000..84d9495057f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csr2022.h b/Build/source/libs/icu/icu-4.6/i18n/csr2022.h
new file mode 100644
index 00000000000..5d34711bdc3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrecog.cpp b/Build/source/libs/icu/icu-4.6/i18n/csrecog.cpp
new file mode 100644
index 00000000000..ba70b1547f8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrecog.h b/Build/source/libs/icu/icu-4.6/i18n/csrecog.h
new file mode 100644
index 00000000000..75cf94f49f4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrmbcs.cpp b/Build/source/libs/icu/icu-4.6/i18n/csrmbcs.cpp
new file mode 100644
index 00000000000..d0c57dedeb3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/csrmbcs.cpp
@@ -0,0 +1,519 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2008, 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 = log10((double)doubleByteCharCount / 4); /*(float)?*/
+ double scaleFactor = 90.0 / maxVal;
+ confidence = (int32_t)(log10((double)commonCharCount+1) * scaleFactor + 10.0);
+
+ confidence = min(confidence, 100);
+ }
+
+ if (confidence < 0) {
+ confidence = 0;
+ }
+
+ return confidence;
+}
+
+CharsetRecog_sjis::~CharsetRecog_sjis()
+{
+ // nothing to do
+}
+
+UBool CharsetRecog_sjis::nextChar(IteratedChar* it, InputText* det) {
+ it->index = it->nextIndex;
+ it->error = FALSE;
+
+ int32_t firstByte = it->charValue = it->nextByte(det);
+
+ if (firstByte < 0) {
+ return FALSE;
+ }
+
+ if (firstByte <= 0x7F || (firstByte > 0xA0 && firstByte <= 0xDF)) {
+ return TRUE;
+ }
+
+ int32_t secondByte = it->nextByte(det);
+ if (secondByte >= 0) {
+ 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.6/i18n/csrmbcs.h b/Build/source/libs/icu/icu-4.6/i18n/csrmbcs.h
new file mode 100644
index 00000000000..371889a1e61
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrsbcs.cpp b/Build/source/libs/icu/icu-4.6/i18n/csrsbcs.cpp
new file mode 100644
index 00000000000..5b55af64751
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrsbcs.h b/Build/source/libs/icu/icu-4.6/i18n/csrsbcs.h
new file mode 100644
index 00000000000..21cbabe5663
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrucode.cpp b/Build/source/libs/icu/icu-4.6/i18n/csrucode.cpp
new file mode 100644
index 00000000000..99a76d850e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrucode.h b/Build/source/libs/icu/icu-4.6/i18n/csrucode.h
new file mode 100644
index 00000000000..315bad6b25e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrutf8.cpp b/Build/source/libs/icu/icu-4.6/i18n/csrutf8.cpp
new file mode 100644
index 00000000000..b87c277fbf9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/csrutf8.h b/Build/source/libs/icu/icu-4.6/i18n/csrutf8.h
new file mode 100644
index 00000000000..10fe287a435
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/curramt.cpp b/Build/source/libs/icu/icu-4.6/i18n/curramt.cpp
new file mode 100644
index 00000000000..f4e1abb0572
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/currfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/currfmt.cpp
new file mode 100644
index 00000000000..133497154b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/currfmt.h b/Build/source/libs/icu/icu-4.6/i18n/currfmt.h
new file mode 100644
index 00000000000..82aae3ec050
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/currpinf.cpp b/Build/source/libs/icu/icu-4.6/i18n/currpinf.cpp
new file mode 100644
index 00000000000..27218ad0131
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/currpinf.cpp
@@ -0,0 +1,384 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, 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)) {
+ currencyPluralPattern =
+ (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(gPluralCountOther);
+ }
+ 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_getByKey(rb, gNumberElementsTag, rb, &ec);
+ rb = ures_getByKey(rb, gLatnTag, rb, &ec);
+ rb = ures_getByKey(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(gPart0,
+ UnicodeString(numberStylePattern, numberStylePatternLen));
+ pattern->findAndReplace(gPart1, gTripleCurrencySign);
+
+ if (hasSeparator) {
+ UnicodeString negPattern(patternChars, ptnLen);
+ negPattern.findAndReplace(gPart0,
+ UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
+ negPattern.findAndReplace(gPart1, gTripleCurrencySign);
+ 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), 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;
+ }
+ 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.6/i18n/currunit.cpp b/Build/source/libs/icu/icu-4.6/i18n/currunit.cpp
new file mode 100644
index 00000000000..47cba6253aa
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/datefmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/datefmt.cpp
new file mode 100644
index 00000000000..9280d2038e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/datefmt.cpp
@@ -0,0 +1,513 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2010, 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.6/i18n/dcfmtsym.cpp b/Build/source/libs/icu/icu-4.6/i18n/dcfmtsym.cpp
new file mode 100644
index 00000000000..eaab453d737
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/dcfmtsym.cpp
@@ -0,0 +1,449 @@
+/*
+*******************************************************************************
+* 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 "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)kCurrencySpacingCount; ++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)kCurrencySpacingCount; ++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[kCurrencySpacingCount] = {
+ 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 < kCurrencySpacingCount; 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 < kCurrencySpacingCount; 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(ECurrencySpacing 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(ECurrencySpacing 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.6/i18n/decContext.c b/Build/source/libs/icu/icu-4.6/i18n/decContext.c
new file mode 100644
index 00000000000..513e0215971
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/decContext.h b/Build/source/libs/icu/icu-4.6/i18n/decContext.h
new file mode 100644
index 00000000000..c25e495e76f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/decNumber.c b/Build/source/libs/icu/icu-4.6/i18n/decNumber.c
new file mode 100644
index 00000000000..ab690782f32
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/decNumber.h b/Build/source/libs/icu/icu-4.6/i18n/decNumber.h
new file mode 100644
index 00000000000..4fe06497754
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/decNumberLocal.h b/Build/source/libs/icu/icu-4.6/i18n/decNumberLocal.h
new file mode 100644
index 00000000000..4a36723ea7e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/decimfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/decimfmt.cpp
new file mode 100644
index 00000000000..85b9085eefd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/decimfmt.cpp
@@ -0,0 +1,4615 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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/curramt.h"
+#include "unicode/currpinf.h"
+#include "unicode/plurrule.h"
+#include "ucurrimp.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "util.h"
+#include "digitlst.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "putilimp.h"
+#include <math.h>
+#include "hash.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,
+ NumberFormat::EStyles 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 = NumberFormat::kNumberStyle;
+ 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_getByKey(resource, fgNumberElements, resource, &status);
+ // TODO : Get the pattern based on the active numbering system for the locale. Right now assumes "latn".
+ resource = ures_getByKey(resource, fgLatn, resource, &status);
+ resource = ures_getByKey(resource, fgPatterns, resource, &status);
+ const UChar *resStr = ures_getStringByKey(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 == NumberFormat::kPluralCurrencyStyle) {
+ 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("other", 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) != -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_getByKey(resource, fgNumberElements, resource, &error);
+ // TODO : Get the pattern based on the active numbering system for the locale. Right now assumes "latn".
+ resource = ures_getByKey(resource, fgLatn, resource, &error);
+ resource = ures_getByKey(resource, fgPatterns, resource, &error);
+ int32_t patLen = 0;
+ const UChar *patResStr = ures_getStringByKey(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("default", 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 char* pluralCountCh;
+ while ((pluralCountCh = keywords->next(NULL, status)) != NULL) {
+ if ( U_SUCCESS(status) ) {
+ UnicodeString pluralCount = UnicodeString(pluralCountCh);
+ 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 char* pluralCountCh;
+ while ((pluralCountCh = keywords->next(NULL, status)) != NULL) {
+ if ( U_SUCCESS(status) ) {
+ UnicodeString pluralCount = UnicodeString(pluralCountCh);
+ 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
+ if (fRoundingIncrement != NULL) {
+ adjustedNum.div(*fRoundingIncrement, status);
+ adjustedNum.toIntegralValue();
+ adjustedNum.mult(*fRoundingIncrement, status);
+ adjustedNum.trim();
+ }
+
+ // 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);
+ }
+
+ 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 the text is composed of the representation of NaN, returns NaN.length
+ const UnicodeString *nan = &getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+ int32_t nanLen = (text.compare(i, nan->length(), *nan)
+ ? 0 : nan->length());
+ if (nanLen) {
+ i += nanLen;
+ if (fFormatWidth > 0 && (fPadPosition == kPadBeforeSuffix ||
+ fPadPosition == kPadAfterSuffix)) {
+ i = skipPadding(text, i);
+ }
+ parsePosition.setIndex(i);
+ result.setDouble(uprv_getNaN());
+ return;
+ }
+
+ // NaN parse failed; start over
+ i = backup;
+
+ // status is used to record whether a number is infinite.
+ UBool status[fgStatusLength];
+ UChar curbuf[4];
+ UChar* currency = parseCurrency ? curbuf : NULL;
+ DigitList *digits = 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 == NumberFormat::kPluralCurrencyStyle) {
+ 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 keyTok = element->key;
+ 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;
+
+ // 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 {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ // Match padding before prefix
+ if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) {
+ position = skipPadding(text, position);
+ }
+
+ // process digits or Inf, find decimal position
+ const UnicodeString *inf = &getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
+ int32_t infLen = (text.compare(position, inf->length(), *inf)
+ ? 0 : inf->length());
+ position += infLen; // infLen is non-zero when it does equal to infinity
+ status[fgStatusInfinite] = (UBool)infLen;
+ if (infLen) {
+ 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);
+
+ const UnicodeString *decimal;
+ if(fCurrencySignCount > fgCurrencySignCountZero) {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ } else {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ }
+ const UnicodeString *grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ UBool sawDecimal = FALSE;
+ UBool sawDigit = FALSE;
+ int32_t backup = -1;
+ int32_t digit;
+ int32_t textLength = text.length(); // One less pointer to follow
+ int32_t groupingLen = grouping->length();
+ int32_t decimalLen = decimal->length();
+
+ // We have to track digitCount ourselves, because digits.fCount will
+ // pin when the maximum allowable digits is reached.
+ int32_t digitCount = 0;
+
+ for (; position < textLength; )
+ {
+ UChar32 ch = text.char32At(position);
+
+ /* We recognize all digit ranges, not only the Latin digit range
+ * '0'..'9'. We do so by using the Character.digit() method,
+ * which converts a valid Unicode digit to the range 0..9.
+ *
+ * The character 'ch' may be a digit. If so, place its value
+ * from 0 to 9 in 'digit'. First try using the locale digit,
+ * which may or MAY NOT be a standard Unicode digit range. If
+ * this fails, try using the standard Unicode digit ranges by
+ * calling Character.digit(). If this also fails, digit will
+ * have a value outside the range 0..9.
+ */
+ digit = ch - zero;
+ if (digit < 0 || digit > 9)
+ {
+ digit = u_charDigitValue(ch);
+ }
+
+ // 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)
+ {
+ // Cancel out backup setting (see grouping handler below)
+ backup = -1;
+
+ sawDigit = TRUE;
+ // output a regular non-zero digit.
+ ++digitCount;
+ parsedNum.append((char)(digit + '0'), err);
+ position += U16_LENGTH(ch);
+ }
+ else if (groupingLen > 0 && !text.compare(position, groupingLen, *grouping) && isGroupingUsed())
+ {
+ // Ignore grouping characters, if we are using them, but require
+ // that they be followed by a digit. Otherwise we backup and
+ // reprocess them.
+ backup = position;
+ position += groupingLen;
+ }
+ else if (!text.compare(position, decimalLen, *decimal) && !isParseIntegerOnly() && !sawDecimal)
+ {
+ // If we're only parsing integers, or if we ALREADY saw the
+ // decimal, then don't parse this one.
+
+ parsedNum.append('.', err);
+ sawDecimal = TRUE;
+ position += decimalLen;
+ }
+ else {
+ const UnicodeString *tmp;
+ tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
+ if (!text.compare(position, tmp->length(), *tmp)) // 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;
+ }
+ }
+ }
+
+ if (backup != -1)
+ {
+ position = backup;
+ }
+
+ // 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);
+ }
+
+ // Match positive and negative suffixes; prefer longest match.
+ if (posMatch >= 0) {
+ posMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, type, currency);
+ }
+ if (negMatch >= 0) {
+ negMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, type, currency);
+ }
+ if (posMatch >= 0 && negMatch >= 0) {
+ if (posMatch > negMatch) {
+ negMatch = -1;
+ } else if (negMatch > posMatch) {
+ posMatch = -1;
+ }
+ }
+
+ // Fail if neither or both
+ if ((posMatch >= 0) == (negMatch >= 0)) {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ position += (posMatch>=0 ? posMatch : negMatch);
+
+ // Match padding before suffix
+ if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) {
+ position = skipPadding(text, position);
+ }
+
+ parsePosition.setIndex(position);
+
+ parsedNum.data()[0] = (posMatch >= 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);
+}
+
+/**
+ * Return the length matched by the given affix, or -1 if none.
+ * Runs of white space in the affix, match runs of white space in
+ * the input. Pattern white space and input white space are
+ * determined differently; see code.
+ * @param affix pattern string, taken as a literal
+ * @param input input text
+ * @param pos offset into input at which to begin matching
+ * @return length of input that matches, or -1 if match failure
+ */
+int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
+ const UnicodeString& input,
+ int32_t pos) {
+ int32_t start = pos;
+ for (int32_t i=0; i<affix.length(); ) {
+ UChar32 c = affix.char32At(i);
+ int32_t len = U16_LENGTH(c);
+ if (uprv_isRuleWhiteSpace(c)) {
+ // We may have a pattern like: \u200F \u0020
+ // and input text like: \u200F \u0020
+ // Note that U+200F and U+0020 are RuleWhiteSpace but only
+ // U+0020 is UWhiteSpace. So we have to first do a direct
+ // match of the run of RULE whitespace in the pattern,
+ // then match any extra characters.
+ UBool literalMatch = FALSE;
+ while (pos < input.length() &&
+ input.char32At(pos) == c) {
+ literalMatch = TRUE;
+ i += len;
+ pos += len;
+ if (i == affix.length()) {
+ break;
+ }
+ c = affix.char32At(i);
+ len = U16_LENGTH(c);
+ if (!uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ }
+
+ // Advance over run in pattern
+ i = skipRuleWhiteSpace(affix, i);
+
+ // Advance over run in input text
+ // Must see at least one white space char in input,
+ // unless we've already matched some characters literally.
+ int32_t s = pos;
+ pos = skipUWhiteSpace(input, pos);
+ if (pos == s && !literalMatch) {
+ return -1;
+ }
+
+ // 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;
+}
+
+/**
+ * Skip over a run of zero or more isRuleWhiteSpace() characters at
+ * pos in text.
+ */
+int32_t DecimalFormat::skipRuleWhiteSpace(const UnicodeString& text, int32_t pos) {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+/**
+ * Skip over a run of zero or more isUWhiteSpace() characters at pos
+ * in text.
+ */
+int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!u_isUWhiteSpace(c)) {
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+/**
+ * Return the length matched by the given affix, or -1 if none.
+ * @param affixPat pattern string
+ * @param input input text
+ * @param pos offset into input at which to begin matching
+ * @param 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);
+ }
+ pos = ppos.getIndex();
+ } else {
+ 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 (uprv_isRuleWhiteSpace(c)) {
+ i = skipRuleWhiteSpace(affixPat, i);
+ }
+ }
+ return pos - start;
+}
+
+/**
+ * Match a single character at text[pos] and return the index of the
+ * next character upon success. Return -1 on failure. If
+ * isRuleWhiteSpace(ch) then match a run of white space in text.
+ */
+int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) {
+ if (uprv_isRuleWhiteSpace(ch)) {
+ // Advance over run of white space in input text
+ // Must see at least one white space char in input
+ int32_t s = pos;
+ pos = skipRuleWhiteSpace(text, pos);
+ if (pos == s) {
+ return -1;
+ }
+ return pos;
+ }
+ return (pos >= 0 && text.char32At(pos) == ch) ?
+ (pos + U16_LENGTH(ch)) : -1;
+}
+
+/**
+ * Match a string at text[pos] and return the index of the next
+ * character upon success. Return -1 on failure. Match a run of
+ * white space in str with a run of white space in text.
+ */
+int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) {
+ for (int32_t i=0; i<str.length() && pos >= 0; ) {
+ UChar32 ch = str.char32At(i);
+ i += U16_LENGTH(ch);
+ if (uprv_isRuleWhiteSpace(ch)) {
+ i = skipRuleWhiteSpace(str, i);
+ }
+ pos = match(text, pos, ch);
+ }
+ return pos;
+}
+
+//------------------------------------------------------------------------------
+// Gets the pointer to the localized decimal format symbols
+
+const DecimalFormatSymbols*
+DecimalFormat::getDecimalFormatSymbols() const
+{
+ return fSymbols;
+}
+
+//------------------------------------------------------------------------------
+// De-owning the current localized symbols and adopt the new symbols.
+
+void
+DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
+{
+ if (symbolsToAdopt == NULL) {
+ return; // do not allow caller to set fSymbols to NULL
+ }
+
+ UBool sameSymbols = FALSE;
+ if (fSymbols != NULL) {
+ sameSymbols = (UBool)(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) ==
+ symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) &&
+ getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) ==
+ symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
+ delete fSymbols;
+ }
+
+ fSymbols = symbolsToAdopt;
+ if (!sameSymbols) {
+ // If the currency symbols are the same, there is no need to recalculate.
+ setCurrencyForSymbols();
+ }
+ expandAffixes(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) == 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 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;
+ // TODO: num of char in plural count
+ char pluralCountChar[10];
+ if (pluralCount->length() >= 10) {
+ break;
+ }
+ pluralCount->extract(0, pluralCount->length(), pluralCountChar);
+ UBool isChoiceFormat;
+ const UChar* s = ucurr_getPluralName(currencyUChars,
+ fSymbols != NULL ? fSymbols->getLocale().getName() :
+ Locale::getDefault().getName(), &isChoiceFormat,
+ pluralCountChar, &len, &ec);
+ affix += UnicodeString(s, len);
+ handler.addAttribute(kCurrencyField, beginIdx, affix.length());
+ } else if(intl) {
+ affix += currencyUChars;
+ 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(s, ec);
+ if (U_SUCCESS(ec)) {
+ umtx_lock(NULL);
+ if (fCurrencyChoice == NULL) {
+ // Cast away const
+ ((DecimalFormat*)this)->fCurrencyChoice = fmt;
+ fmt = NULL;
+ }
+ umtx_unlock(NULL);
+ delete fmt;
+ }
+ }
+ // We could almost return null or "" here, since the
+ // expanded affixes are almost not used at all
+ // in this situation. However, one method --
+ // toPattern() -- still does use the expanded
+ // affixes, in order to set up a padding
+ // pattern. We use the CURRENCY_SIGN as a
+ // placeholder.
+ affix.append(kCurrencySign);
+ } else {
+ if (fCurrencyChoice != NULL) {
+ FieldPosition pos(0); // ignored
+ if (number < 0) {
+ number = -number;
+ }
+ fCurrencyChoice->format(number, affix, pos);
+ } else {
+ // We only arrive here if the currency choice
+ // format in the locale data is INVALID.
+ affix += currencyUChars;
+ 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 == NumberFormat::kPluralCurrencyStyle) {
+ 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 == NumberFormat::kPluralCurrencyStyle) {
+ // 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) != -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) != -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;
+ }
+ 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;
+ }
+ 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 keyTok = element->key;
+ 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 keyTok = element->key;
+ 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.6/i18n/digitlst.cpp b/Build/source/libs/icu/icu-4.6/i18n/digitlst.cpp
new file mode 100644
index 00000000000..4a146f44281
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/digitlst.cpp
@@ -0,0 +1,861 @@
+/*
+**********************************************************************
+* Copyright (C) 1997-2010, 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;
+}
+
+
+// -------------------------------------
+
+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;
+ 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. Round if there is a fractional part.
+ * Return zero if the number cannot be represented.
+ */
+int64_t DigitList::getInt64() /*const*/ {
+ // Round if non-integer. (Truncate or round?)
+ // 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;
+ }
+ decNumber *workingNum = fDecNumber;
+
+ if (fDecNumber->exponent != 0) {
+ // Force to an integer, with zero exponent, rounding if necessary.
+ DigitList copy(*this);
+ DigitList zero;
+ uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
+ workingNum = copy.fDecNumber;
+ }
+
+ uint64_t value = 0;
+ int32_t numDigits = workingNum->digits;
+ for (int i = numDigits-1; i>=0 ; --i) {
+ int v = workingNum->lsu[i];
+ value = value * (uint64_t)10 + (uint64_t)v;
+ }
+ if (decNumberIsNegative(workingNum)) {
+ 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 (numDigits == 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.6/i18n/digitlst.h b/Build/source/libs/icu/icu-4.6/i18n/digitlst.h
new file mode 100644
index 00000000000..c95fb5f13c1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/digitlst.h
@@ -0,0 +1,399 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 1997-2010, 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;
+ */
+
+private:
+
+ decContext fContext;
+ 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.6/i18n/dtfmtsym.cpp b/Build/source/libs/icu/icu-4.6/i18n/dtfmtsym.cpp
new file mode 100644
index 00000000000..78f2069a7a1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/dtfmtsym.cpp
@@ -0,0 +1,1576 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2009, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File DTFMTSYM.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 07/21/98 stephen Added getZoneIndex
+* Changed weekdays/short weekdays to be one-based
+* 06/14/99 stephen Removed SimpleDateFormat::fgTimeZoneDataSuffix
+* 11/16/99 weiv Added 'Y' and 'e' to fgPatternChars
+* 03/27/00 weiv Keeping resource bundle around!
+* 06/30/05 emmons Added eraNames, narrow month/day, standalone context
+* 10/12/05 emmons Added setters for eraNames, month/day by width/context
+*******************************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/ustring.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/msgfmt.h"
+#include "cpputils.h"
+#include "ucln_in.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "gregoimp.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "zstrfmt.h"
+#include "ureslocs.h"
+
+// *****************************************************************************
+// class DateFormatSymbols
+// *****************************************************************************
+
+/**
+ * These are static arrays we use only in the case where we have no
+ * resource data.
+ */
+
+#define PATTERN_CHARS_LEN 30
+
+/**
+ * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
+ * locales use the same these unlocalized pattern characters.
+ */
+static const UChar gPatternChars[] = {
+ // GyMdkHmsSEDFwWahKzYeugAZvcLQqV
+ 0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
+ 0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
+ 0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56, 0
+};
+
+/* length of an array */
+#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
+
+//------------------------------------------------------
+// Strings of last resort. These are only used if we have no resource
+// files. They aren't designed for actual use, just for backup.
+
+// These are the month names and abbreviations of last resort.
+static const UChar gLastResortMonthNames[13][3] =
+{
+ {0x0030, 0x0031, 0x0000}, /* "01" */
+ {0x0030, 0x0032, 0x0000}, /* "02" */
+ {0x0030, 0x0033, 0x0000}, /* "03" */
+ {0x0030, 0x0034, 0x0000}, /* "04" */
+ {0x0030, 0x0035, 0x0000}, /* "05" */
+ {0x0030, 0x0036, 0x0000}, /* "06" */
+ {0x0030, 0x0037, 0x0000}, /* "07" */
+ {0x0030, 0x0038, 0x0000}, /* "08" */
+ {0x0030, 0x0039, 0x0000}, /* "09" */
+ {0x0031, 0x0030, 0x0000}, /* "10" */
+ {0x0031, 0x0031, 0x0000}, /* "11" */
+ {0x0031, 0x0032, 0x0000}, /* "12" */
+ {0x0031, 0x0033, 0x0000} /* "13" */
+};
+
+// These are the weekday names and abbreviations of last resort.
+static const UChar gLastResortDayNames[8][2] =
+{
+ {0x0030, 0x0000}, /* "0" */
+ {0x0031, 0x0000}, /* "1" */
+ {0x0032, 0x0000}, /* "2" */
+ {0x0033, 0x0000}, /* "3" */
+ {0x0034, 0x0000}, /* "4" */
+ {0x0035, 0x0000}, /* "5" */
+ {0x0036, 0x0000}, /* "6" */
+ {0x0037, 0x0000} /* "7" */
+};
+
+// These are the quarter names and abbreviations of last resort.
+static const UChar gLastResortQuarters[4][2] =
+{
+ {0x0031, 0x0000}, /* "1" */
+ {0x0032, 0x0000}, /* "2" */
+ {0x0033, 0x0000}, /* "3" */
+ {0x0034, 0x0000}, /* "4" */
+};
+
+// These are the am/pm and BC/AD markers of last resort.
+static const UChar gLastResortAmPmMarkers[2][3] =
+{
+ {0x0041, 0x004D, 0x0000}, /* "AM" */
+ {0x0050, 0x004D, 0x0000} /* "PM" */
+};
+
+static const UChar gLastResortEras[2][3] =
+{
+ {0x0042, 0x0043, 0x0000}, /* "BC" */
+ {0x0041, 0x0044, 0x0000} /* "AD" */
+};
+
+
+// These are the zone strings of last resort.
+static const UChar gLastResortZoneStrings[7][4] =
+{
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000} /* "GMT" */
+};
+
+static const UChar gLastResortGmtFormat[] =
+ {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
+
+static const UChar gLastResortGmtHourFormats[4][10] =
+{
+ {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* -HH:mm:ss */
+ {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000}, /* -HH:mm */
+ {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* +HH:mm:ss */
+ {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000} /* +HH:mm */
+};
+
+/* Sizes for the last resort string arrays */
+typedef enum LastResortSize {
+ kMonthNum = 13,
+ kMonthLen = 3,
+
+ kDayNum = 8,
+ kDayLen = 2,
+
+ kAmPmNum = 2,
+ kAmPmLen = 3,
+
+ kQuarterNum = 4,
+ kQuarterLen = 2,
+
+ kEraNum = 2,
+ kEraLen = 3,
+
+ kZoneNum = 5,
+ kZoneLen = 4,
+
+ kGmtHourNum = 4,
+ kGmtHourLen = 10
+} LastResortSize;
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
+
+#define kSUPPLEMENTAL "supplementalData"
+
+/**
+ * These are the tags we expect to see in normal resource bundle files associated
+ * with a locale and calendar
+ */
+static const char gErasTag[]="eras";
+static const char gMonthNamesTag[]="monthNames";
+static const char gDayNamesTag[]="dayNames";
+static const char gNamesWideTag[]="wide";
+static const char gNamesAbbrTag[]="abbreviated";
+static const char gNamesNarrowTag[]="narrow";
+static const char gNamesStandaloneTag[]="stand-alone";
+static const char gAmPmMarkersTag[]="AmPmMarkers";
+static const char gQuartersTag[]="quarters";
+
+static const char gZoneStringsTag[]="zoneStrings";
+static const char gGmtFormatTag[]="gmtFormat";
+static const char gHourFormatTag[]="hourFormat";
+
+static const char gLocalPatternCharsTag[]="localPatternChars";
+
+static UMTX LOCK;
+
+/**
+ * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
+ * Work around this.
+ */
+static inline UnicodeString* newUnicodeStringArray(size_t count) {
+ return new UnicodeString[count ? count : 1];
+}
+
+//------------------------------------------------------
+
+DateFormatSymbols::DateFormatSymbols(const Locale& locale,
+ UErrorCode& status)
+ : UObject()
+{
+ initializeData(locale, NULL, status);
+}
+
+DateFormatSymbols::DateFormatSymbols(UErrorCode& status)
+ : UObject()
+{
+ initializeData(Locale::getDefault(), NULL, status, TRUE);
+}
+
+
+DateFormatSymbols::DateFormatSymbols(const Locale& locale,
+ const char *type,
+ UErrorCode& status)
+ : UObject()
+{
+ initializeData(locale, type, status);
+}
+
+DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status)
+ : UObject()
+{
+ initializeData(Locale::getDefault(), type, status, TRUE);
+}
+
+DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other)
+ : UObject(other)
+{
+ copyData(other);
+}
+
+void
+DateFormatSymbols::assignArray(UnicodeString*& dstArray,
+ int32_t& dstCount,
+ const UnicodeString* srcArray,
+ int32_t srcCount)
+{
+ // assignArray() is only called by copyData(), which in turn implements the
+ // copy constructor and the assignment operator.
+ // All strings in a DateFormatSymbols object are created in one of the following
+ // three ways that all allow to safely use UnicodeString::fastCopyFrom():
+ // - readonly-aliases from resource bundles
+ // - readonly-aliases or allocated strings from constants
+ // - safely cloned strings (with owned buffers) from setXYZ() functions
+ //
+ // Note that this is true for as long as DateFormatSymbols can be constructed
+ // only from a locale bundle or set via the cloning API,
+ // *and* for as long as all the strings are in *private* fields, preventing
+ // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()).
+ dstCount = srcCount;
+ dstArray = newUnicodeStringArray(srcCount);
+ if(dstArray != NULL) {
+ int32_t i;
+ for(i=0; i<srcCount; ++i) {
+ dstArray[i].fastCopyFrom(srcArray[i]);
+ }
+ }
+}
+
+/**
+ * Create a copy, in fZoneStrings, of the given zone strings array. The
+ * member variables fZoneStringsRowCount and fZoneStringsColCount should
+ * be set already by the caller.
+ */
+void
+DateFormatSymbols::createZoneStrings(const UnicodeString *const * otherStrings)
+{
+ int32_t row, col;
+ 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);
+ fGmtFormat = other.fGmtFormat;
+ assignArray(fGmtHourFormats, fGmtHourFormatsCount, other.fGmtHourFormats, other.fGmtHourFormatsCount);
+
+ if (other.fZoneStrings != NULL) {
+ fZoneStringsColCount = other.fZoneStringsColCount;
+ fZoneStringsRowCount = other.fZoneStringsRowCount;
+ createZoneStrings((const UnicodeString**)other.fZoneStrings);
+
+ } else {
+ fZoneStrings = NULL;
+ fZoneStringsColCount = 0;
+ fZoneStringsRowCount = 0;
+ }
+ fZSFLocale = other.fZSFLocale;
+ // Other zone strings data is created on demand
+ fZoneStringFormat = NULL;
+ fLocaleZoneStrings = NULL;
+ fZSFCachePtr = NULL;
+ fZSFLocal = NULL;
+
+ // fastCopyFrom() - see assignArray comments
+ fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
+}
+
+/**
+ * Assignment operator.
+ */
+DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
+{
+ dispose();
+ copyData(other);
+
+ return *this;
+}
+
+DateFormatSymbols::~DateFormatSymbols()
+{
+ dispose();
+}
+
+void DateFormatSymbols::dispose()
+{
+ if (fEras) delete[] fEras;
+ if (fEraNames) delete[] fEraNames;
+ if (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);
+ }
+ if (fZSFLocal) {
+ delete fZSFLocal;
+ }
+ if (fZSFCachePtr) {
+ delete fZSFCachePtr;
+ }
+
+ fZoneStrings = NULL;
+ fLocaleZoneStrings = NULL;
+ fZoneStringsRowCount = 0;
+ fZoneStringsColCount = 0;
+
+ fZoneStringFormat = NULL;
+ fZSFLocal = NULL;
+ fZSFCachePtr = NULL;
+}
+
+UBool
+DateFormatSymbols::arrayCompare(const UnicodeString* array1,
+ const UnicodeString* array2,
+ int32_t count)
+{
+ if (array1 == array2) return TRUE;
+ while (count>0)
+ {
+ --count;
+ if (array1[count] != array2[count]) return FALSE;
+ }
+ return TRUE;
+}
+
+UBool
+DateFormatSymbols::operator==(const DateFormatSymbols& other) const
+{
+ // First do cheap comparisons
+ if (this == &other) {
+ return TRUE;
+ }
+ if (fErasCount == other.fErasCount &&
+ fEraNamesCount == other.fEraNamesCount &&
+ 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 &&
+ 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 ZoneStringFormat*
+DateFormatSymbols::getZoneStringFormat(void) const {
+ umtx_lock(&LOCK);
+ if (fZoneStringFormat == NULL) {
+ ((DateFormatSymbols*)this)->initZoneStringFormat();
+ }
+ umtx_unlock(&LOCK);
+ return fZoneStringFormat;
+}
+
+void
+DateFormatSymbols::initZoneStringFormat(void) {
+ if (fZoneStringFormat == NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (fZoneStrings) {
+ // Create an istance of ZoneStringFormat by the custom zone strings array
+ fZSFLocal = new ZoneStringFormat(fZoneStrings, fZoneStringsRowCount,
+ fZoneStringsColCount, status);
+ if (U_FAILURE(status)) {
+ delete fZSFLocal;
+ } else {
+ fZoneStringFormat = (const ZoneStringFormat*)fZSFLocal;
+ }
+ } else {
+ fZSFCachePtr = ZoneStringFormat::getZoneStringFormat(fZSFLocale, status);
+ if (U_FAILURE(status)) {
+ delete fZSFCachePtr;
+ } else {
+ fZoneStringFormat = fZSFCachePtr->get();
+ }
+ }
+ }
+}
+
+const UnicodeString**
+DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
+{
+ const UnicodeString **result = NULL;
+
+ umtx_lock(&LOCK);
+ if (fZoneStrings == NULL) {
+ if (fLocaleZoneStrings == NULL) {
+ ((DateFormatSymbols*)this)->initZoneStringsArray();
+ }
+ result = (const UnicodeString**)fLocaleZoneStrings;
+ } else {
+ result = (const UnicodeString**)fZoneStrings;
+ }
+ rowCount = fZoneStringsRowCount;
+ columnCount = fZoneStringsColCount;
+ umtx_unlock(&LOCK);
+
+ return result;
+}
+
+void
+DateFormatSymbols::initZoneStringsArray(void) {
+ if (fZoneStrings == NULL && fLocaleZoneStrings == NULL) {
+ if (fZoneStringFormat == NULL) {
+ initZoneStringFormat();
+ }
+ if (fZoneStringFormat) {
+ UErrorCode status = U_ZERO_ERROR;
+ fLocaleZoneStrings = fZoneStringFormat->createZoneStringsArray(uprv_getUTCtime() /* use current time */,
+ fZoneStringsRowCount, fZoneStringsColCount, status);
+ }
+ }
+}
+
+void
+DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount)
+{
+ // since deleting a 2-d array is a pain in the butt, we offload that task to
+ // a separate function
+ disposeZoneStrings();
+ // 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;
+
+ fZoneStringFormat = NULL;
+ fZSFLocal = NULL;
+ fZSFCachePtr = NULL;
+
+ // We need to preserve the requested locale for
+ // lazy ZoneStringFormat instantiation. ZoneStringFormat
+ // is region sensitive, thus, bundle locale bundle's locale
+ // is not sufficient.
+ fZSFLocale = locale;
+
+ if (U_FAILURE(status)) return;
+
+ /**
+ * Retrieve the string arrays we need from the resource bundle file.
+ * We cast away const here, but that's okay; we won't delete any of
+ * these.
+ */
+ CalendarData calData(locale, type, status);
+
+ /**
+ * Use the localeBundle for getting zone GMT formatting patterns
+ */
+ UResourceBundle *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);
+ 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 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.6/i18n/dtitv_impl.h b/Build/source/libs/icu/icu-4.6/i18n/dtitv_impl.h
new file mode 100644
index 00000000000..009d9a8b4ae
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/dtitvfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/dtitvfmt.cpp
new file mode 100644
index 00000000000..8bb6c6e9f4b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/dtitvfmt.cpp
@@ -0,0 +1,1432 @@
+/*******************************************************************************
+* Copyright (C) 2008-2010, 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;
+}
+
+
+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]);
+ 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]);
+ 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("v", "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.6/i18n/dtitvinf.cpp b/Build/source/libs/icu/icu-4.6/i18n/dtitvinf.cpp
new file mode 100644
index 00000000000..58a98e03984
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/dtitvinf.cpp
@@ -0,0 +1,660 @@
+/*******************************************************************************
+* Copyright (C) 2008-2010, 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 ) {
+ UResourceBundle* oneRes = ures_getByIndex(itvDtPtnResource, index,
+ NULL, &status);
+ if ( U_SUCCESS(status) ) {
+ const char* skeleton = ures_getKey(oneRes);
+ if ( skeleton == NULL ||
+ skeletonSet.geti(UnicodeString(skeleton)) == 1 ) {
+ ures_close(oneRes);
+ continue;
+ }
+ skeletonSet.puti(UnicodeString(skeleton), 1, status);
+ if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
+ ures_close(oneRes);
+ continue; // fallback
+ }
+
+ UResourceBundle* intervalPatterns = ures_getByKey(
+ itvDtPtnResource, skeleton, NULL, &status);
+
+ if ( U_FAILURE(status) ) {
+ ures_close(intervalPatterns);
+ ures_close(oneRes);
+ break;
+ }
+ if ( intervalPatterns == NULL ) {
+ ures_close(intervalPatterns);
+ ures_close(oneRes);
+ continue;
+ }
+
+ const UChar* pattern;
+ const char* key;
+ int32_t ptLength;
+ int32_t ptnNum = ures_getSize(intervalPatterns);
+ int32_t ptnIndex;
+ for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
+ pattern = ures_getNextString(intervalPatterns, &ptLength, &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(skeleton, calendarField, pattern,status);
+ }
+ }
+ ures_close(intervalPatterns);
+ }
+ ures_close(oneRes);
+ }
+ }
+ 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 ) {
+ UChar zstr[2];
+ UChar vstr[2];
+ zstr[0]=CHAR_Z;
+ vstr[0]=CHAR_V;
+ zstr[1]=0;
+ vstr[1]=0;
+ copySkeleton = skeleton;
+ copySkeleton.findAndReplace(zstr, vstr);
+ 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 keyTok = element->key;
+ 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;
+ }
+ 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.6/i18n/dtptngen.cpp b/Build/source/libs/icu/icu-4.6/i18n/dtptngen.cpp
new file mode 100644
index 00000000000..bb4dd27b415
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/dtptngen.cpp
@@ -0,0 +1,2159 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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_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, formattedPattern;
+ 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, FALSE, options);
+ //resultPattern = tempPattern;
+ 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;
+ formattedPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, emptyStr, err);
+ lastMissingFieldMask = distanceInfo->missingFieldMask;
+ }
+ }
+ return formattedPattern;
+}
+
+int32_t
+DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) {
+ if ( foundMask==0 ) {
+ return 0;
+ }
+ int32_t i=0;
+ while (foundMask!=0) {
+ foundMask >>=1;
+ ++i;
+ }
+ if (i-1 >UDATPG_ZONE_FIELD) {
+ return UDATPG_ZONE_FIELD;
+ }
+ else
+ return i-1;
+}
+
+void
+DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err)
+{
+ fAvailableFormatKeyHash->puti(key, 1, err);
+}
+
+UBool
+DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
+ return (UBool)(fAvailableFormatKeyHash->geti(key) == 1);
+}
+
+void
+DateTimePatternGenerator::copyHashtable(Hashtable *other, 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.6/i18n/dtptngen_impl.h b/Build/source/libs/icu/icu-4.6/i18n/dtptngen_impl.h
new file mode 100644
index 00000000000..25afef8138d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/dtptngen_impl.h
@@ -0,0 +1,259 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2009, 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.6/i18n/dtrule.cpp b/Build/source/libs/icu/icu-4.6/i18n/dtrule.cpp
new file mode 100644
index 00000000000..c2eeb052a40
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/esctrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/esctrn.cpp
new file mode 100644
index 00000000000..93f13f5816c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/esctrn.h b/Build/source/libs/icu/icu-4.6/i18n/esctrn.h
new file mode 100644
index 00000000000..96872b91684
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ethpccal.cpp b/Build/source/libs/icu/icu-4.6/i18n/ethpccal.cpp
new file mode 100644
index 00000000000..9317dead0ae
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ethpccal.h b/Build/source/libs/icu/icu-4.6/i18n/ethpccal.h
new file mode 100644
index 00000000000..01db826a79f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/fmtable.cpp b/Build/source/libs/icu/icu-4.6/i18n/fmtable.cpp
new file mode 100644
index 00000000000..4c755bf5e90
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/fmtable.cpp
@@ -0,0 +1,852 @@
+/*
+*******************************************************************************
+* 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
+
+#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;
+ }
+}
+
+// -------------------------------------
+int64_t
+Formattable::getInt64(UErrorCode& status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ switch (fType) {
+ case Formattable::kLong:
+ case Formattable::kInt64:
+ return fValue.fInt64;
+ case Formattable::kDouble:
+ if (fValue.fDouble >= U_INT64_MAX) {
+ status = U_INVALID_FORMAT_ERROR;
+ return U_INT64_MAX;
+ } else if (fValue.fDouble <= U_INT64_MIN) {
+ status = U_INVALID_FORMAT_ERROR;
+ return U_INT64_MIN;
+ } else {
+ return (int64_t)fValue.fDouble;
+ }
+ case Formattable::kObject:
+ 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().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.6/i18n/fmtable_cnv.cpp b/Build/source/libs/icu/icu-4.6/i18n/fmtable_cnv.cpp
new file mode 100644
index 00000000000..8e9645402e5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/format.cpp b/Build/source/libs/icu/icu-4.6/i18n/format.cpp
new file mode 100644
index 00000000000..701b489fff7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/fphdlimp.cpp b/Build/source/libs/icu/icu-4.6/i18n/fphdlimp.cpp
new file mode 100644
index 00000000000..9d94a411488
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/fphdlimp.h b/Build/source/libs/icu/icu-4.6/i18n/fphdlimp.h
new file mode 100644
index 00000000000..cd5c314a888
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/fpositer.cpp b/Build/source/libs/icu/icu-4.6/i18n/fpositer.cpp
new file mode 100644
index 00000000000..69712642b22
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/funcrepl.cpp b/Build/source/libs/icu/icu-4.6/i18n/funcrepl.cpp
new file mode 100644
index 00000000000..03d71834762
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/funcrepl.h b/Build/source/libs/icu/icu-4.6/i18n/funcrepl.h
new file mode 100644
index 00000000000..f58d613bb5a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/funcrepl.h
@@ -0,0 +1,123 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 02/04/2002 aliu Creation.
+**********************************************************************
+*/
+
+#ifndef FUNCREPL_H
+#define FUNCREPL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifunct.h"
+#include "unicode/unirepl.h"
+
+U_NAMESPACE_BEGIN
+
+class Transliterator;
+
+/**
+ * A replacer that calls a transliterator to generate its output text.
+ * The input text to the transliterator is the output of another
+ * UnicodeReplacer object. That is, this replacer wraps another
+ * replacer with a transliterator.
+ *
+ * @author Alan Liu
+ */
+class FunctionReplacer : public UnicodeFunctor, public UnicodeReplacer {
+
+ private:
+
+ /**
+ * The transliterator. Must not be null. OWNED.
+ */
+ Transliterator* translit;
+
+ /**
+ * The replacer object. This generates text that is then
+ * processed by 'translit'. Must not be null. OWNED.
+ */
+ UnicodeFunctor* replacer;
+
+ public:
+
+ /**
+ * Construct a replacer that takes the output of the given
+ * replacer, passes it through the given transliterator, and emits
+ * the result as output.
+ */
+ FunctionReplacer(Transliterator* adoptedTranslit,
+ UnicodeFunctor* adoptedReplacer);
+
+ /**
+ * Copy constructor.
+ */
+ FunctionReplacer(const FunctionReplacer& other);
+
+ /**
+ * Destructor
+ */
+ virtual ~FunctionReplacer();
+
+ /**
+ * Implement UnicodeFunctor
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ */
+ virtual UnicodeReplacer* toReplacer() const;
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor);
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& rule,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Implement UnicodeReplacer
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * UnicodeFunctor API
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/gregocal.cpp b/Build/source/libs/icu/icu-4.6/i18n/gregocal.cpp
new file mode 100644
index 00000000000..3bc77cf1494
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/gregoimp.cpp b/Build/source/libs/icu/icu-4.6/i18n/gregoimp.cpp
new file mode 100644
index 00000000000..08a3fbcef4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/gregoimp.h b/Build/source/libs/icu/icu-4.6/i18n/gregoimp.h
new file mode 100644
index 00000000000..f65d1410139
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/hebrwcal.cpp b/Build/source/libs/icu/icu-4.6/i18n/hebrwcal.cpp
new file mode 100644
index 00000000000..3a6ef439412
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/hebrwcal.h b/Build/source/libs/icu/icu-4.6/i18n/hebrwcal.h
new file mode 100644
index 00000000000..76f100fea95
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/i18n.rc b/Build/source/libs/icu/icu-4.6/i18n/i18n.rc
new file mode 100644
index 00000000000..1b624ad6b55
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/i18n.vcxproj b/Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj
new file mode 100644
index 00000000000..66ebda0952b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj
@@ -0,0 +1,1472 @@
+<?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>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\icuin46.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>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\icuin46d.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>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\icuin46.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>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\icuin46d.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="bms.cpp" />
+ <ClCompile Include="bmsearch.cpp" />
+ <ClCompile Include="bocsu.c" />
+ <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="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="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="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="udatpg.cpp" />
+ <ClCompile Include="ulocdata.c" />
+ <ClCompile Include="umsg.cpp" />
+ <ClCompile Include="unum.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="zstrfmt.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\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="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" />
+ <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="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\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\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="zstrfmt.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>
diff --git a/Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj.filters b/Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj.filters
new file mode 100644
index 00000000000..d1ea38b64c3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/i18n.vcxproj.filters
@@ -0,0 +1,955 @@
+<?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="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="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="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="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="zstrfmt.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>
+ </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="unicode\currpinf.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
+ <ClInclude Include="decContext.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="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="zstrfmt.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>
+ </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\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\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>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Build/source/libs/icu/icu-4.6/i18n/indiancal.cpp b/Build/source/libs/icu/icu-4.6/i18n/indiancal.cpp
new file mode 100644
index 00000000000..526cfc44d2a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/indiancal.h b/Build/source/libs/icu/icu-4.6/i18n/indiancal.h
new file mode 100644
index 00000000000..ff841fbfacb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/inputext.cpp b/Build/source/libs/icu/icu-4.6/i18n/inputext.cpp
new file mode 100644
index 00000000000..e5a8ee1868a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/inputext.h b/Build/source/libs/icu/icu-4.6/i18n/inputext.h
new file mode 100644
index 00000000000..0c5973d8eb2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/islamcal.cpp b/Build/source/libs/icu/icu-4.6/i18n/islamcal.cpp
new file mode 100644
index 00000000000..5867091751e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/islamcal.cpp
@@ -0,0 +1,545 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2010, 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.
+
+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, 30}, // DAY_OF_MONTH
+ { 1, 1, 354, 355}, // DAY_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
+ { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
+ { 1, 1, 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.6/i18n/islamcal.h b/Build/source/libs/icu/icu-4.6/i18n/islamcal.h
new file mode 100644
index 00000000000..e3647bc0ffd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/japancal.cpp b/Build/source/libs/icu/icu-4.6/i18n/japancal.cpp
new file mode 100644
index 00000000000..ad95b7c04bc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/japancal.h b/Build/source/libs/icu/icu-4.6/i18n/japancal.h
new file mode 100644
index 00000000000..4219d6a5231
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/locdspnm.cpp b/Build/source/libs/icu/icu-4.6/i18n/locdspnm.cpp
new file mode 100644
index 00000000000..83ce4ec4a61
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/locdspnm.cpp
@@ -0,0 +1,694 @@
+/*
+*******************************************************************************
+* Copyright (C) 2010, 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("=")
+ .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.6/i18n/measfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/measfmt.cpp
new file mode 100644
index 00000000000..eaa37a24850
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/measure.cpp b/Build/source/libs/icu/icu-4.6/i18n/measure.cpp
new file mode 100644
index 00000000000..7b91677a3c0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/msgfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/msgfmt.cpp
new file mode 100644
index 00000000000..b529246683e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/msgfmt.cpp
@@ -0,0 +1,1858 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2010, 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/msgfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/plurfmt.h"
+#include "unicode/selfmt.h"
+#include "unicode/ustring.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/uchar.h"
+#include "unicode/umsg.h"
+#include "unicode/rbnf.h"
+#include "cmemory.h"
+#include "msgfmt_impl.h"
+#include "util.h"
+#include "uassert.h"
+#include "ustrfmt.h"
+#include "uvector.h"
+
+// *****************************************************************************
+// class MessageFormat
+// *****************************************************************************
+
+#define COMMA ((UChar)0x002C)
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define LEFT_CURLY_BRACE ((UChar)0x007B)
+#define RIGHT_CURLY_BRACE ((UChar)0x007D)
+
+//---------------------------------------
+// static data
+
+static const UChar ID_EMPTY[] = {
+ 0 /* empty string, used for default so that null can mark end of list */
+};
+
+static const UChar ID_NUMBER[] = {
+ 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
+};
+static const UChar ID_DATE[] = {
+ 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
+};
+static const UChar ID_TIME[] = {
+ 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
+};
+static const UChar ID_CHOICE[] = {
+ 0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0 /* "choice" */
+};
+static const UChar ID_SPELLOUT[] = {
+ 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
+};
+static const UChar ID_ORDINAL[] = {
+ 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
+};
+static const UChar ID_DURATION[] = {
+ 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
+};
+static const UChar ID_PLURAL[] = {
+ 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0 /* "plural" */
+};
+static const UChar ID_SELECT[] = {
+ 0x73, 0x65, 0x6C, 0x65, 0x63, 0x74, 0 /* "select" */
+};
+
+// MessageFormat Type List Number, Date, Time or Choice
+static const UChar * const TYPE_IDS[] = {
+ ID_EMPTY,
+ ID_NUMBER,
+ ID_DATE,
+ ID_TIME,
+ ID_CHOICE,
+ ID_SPELLOUT,
+ ID_ORDINAL,
+ ID_DURATION,
+ ID_PLURAL,
+ ID_SELECT,
+ NULL,
+};
+
+static const UChar ID_CURRENCY[] = {
+ 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
+};
+static const UChar ID_PERCENT[] = {
+ 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
+};
+static const UChar ID_INTEGER[] = {
+ 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
+};
+
+// NumberFormat modifier list, default, currency, percent or integer
+static const UChar * const NUMBER_STYLE_IDS[] = {
+ ID_EMPTY,
+ ID_CURRENCY,
+ ID_PERCENT,
+ ID_INTEGER,
+ NULL,
+};
+
+static const UChar ID_SHORT[] = {
+ 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
+};
+static const UChar ID_MEDIUM[] = {
+ 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
+};
+static const UChar ID_LONG[] = {
+ 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
+};
+static const UChar ID_FULL[] = {
+ 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
+};
+
+// DateFormat modifier list, default, short, medium, long or full
+static const UChar * const DATE_STYLE_IDS[] = {
+ ID_EMPTY,
+ ID_SHORT,
+ ID_MEDIUM,
+ ID_LONG,
+ ID_FULL,
+ NULL,
+};
+
+static const U_NAMESPACE_QUALIFIER DateFormat::EStyle DATE_STYLES[] = {
+ U_NAMESPACE_QUALIFIER DateFormat::kDefault,
+ U_NAMESPACE_QUALIFIER DateFormat::kShort,
+ U_NAMESPACE_QUALIFIER DateFormat::kMedium,
+ U_NAMESPACE_QUALIFIER DateFormat::kLong,
+ U_NAMESPACE_QUALIFIER DateFormat::kFull,
+};
+
+static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration)
+
+//--------------------------------------------------------------------
+
+/**
+ * Convert a string to an unsigned decimal, ignoring rule whitespace.
+ * @return a non-negative number if successful, or a negative number
+ * upon failure.
+ */
+static int32_t stou(const UnicodeString& string) {
+ int32_t n = 0;
+ int32_t count = 0;
+ UChar32 c;
+ for (int32_t i=0; i<string.length(); i+=U16_LENGTH(c)) {
+ c = string.char32At(i);
+ if (uprv_isRuleWhiteSpace(c)) {
+ continue;
+ }
+ int32_t d = u_digit(c, 10);
+ if (d < 0 || ++count > 10) {
+ return -1;
+ }
+ n = 10*n + d;
+ }
+ return n;
+}
+
+/**
+ * Convert an integer value to a string and append the result to
+ * the given UnicodeString.
+ */
+static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
+ UChar temp[16];
+ uprv_itou(temp,16,i,10,0); // 10 == radix
+ appendTo.append(temp);
+ return appendTo;
+}
+
+/*
+ * A structure representing one subformat of this MessageFormat.
+ * Each subformat has a Format object, an offset into the plain
+ * pattern text fPattern, and an argument number. The argument
+ * number corresponds to the array of arguments to be formatted.
+ * @internal
+ */
+class MessageFormat::Subformat : public UMemory {
+public:
+ /**
+ * @internal
+ */
+ Format* format; // formatter
+ /**
+ * @internal
+ */
+ int32_t offset; // offset into fPattern
+ /**
+ * @internal
+ */
+ // TODO (claireho) or save the number to argName and use itos to convert to number.=> we need this number
+ int32_t argNum; // 0-based argument number
+ /**
+ * @internal
+ */
+ UnicodeString* argName; // argument name or number
+
+ /**
+ * Clone that.format and assign it to this.format
+ * Do NOT delete this.format
+ * @internal
+ */
+ Subformat& operator=(const Subformat& that) {
+ if (this != &that) {
+ format = that.format ? that.format->clone() : NULL;
+ offset = that.offset;
+ argNum = that.argNum;
+ argName = (that.argNum==-1) ? new UnicodeString(*that.argName): NULL;
+ }
+ return *this;
+ }
+
+ /**
+ * @internal
+ */
+ UBool operator==(const Subformat& that) const {
+ // Do cheap comparisons first
+ return offset == that.offset &&
+ argNum == that.argNum &&
+ ((argName == that.argName) ||
+ (*argName == *that.argName)) &&
+ ((format == that.format) || // handles NULL
+ (*format == *that.format));
+ }
+
+ /**
+ * @internal
+ */
+ UBool operator!=(const Subformat& that) const {
+ return !operator==(that);
+ }
+};
+
+// -------------------------------------
+// Creates a MessageFormat instance based on the pattern.
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ UErrorCode& success)
+: fLocale(Locale::getDefault()), // Uses the default locale
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ idStart(UCHAR_ID_START),
+ idContinue(UCHAR_ID_CONTINUE),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ isArgNumeric(TRUE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
+ !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ applyPattern(pattern, success);
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UErrorCode& success)
+: fLocale(newLocale),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ idStart(UCHAR_ID_START),
+ idContinue(UCHAR_ID_CONTINUE),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ isArgNumeric(TRUE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
+ !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ applyPattern(pattern, success);
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UParseError& parseError,
+ UErrorCode& success)
+: fLocale(newLocale),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ idStart(UCHAR_ID_START),
+ idContinue(UCHAR_ID_CONTINUE),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ isArgNumeric(TRUE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
+ !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ applyPattern(pattern, parseError, success);
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+MessageFormat::MessageFormat(const MessageFormat& that)
+: Format(that),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ idStart(UCHAR_ID_START),
+ idContinue(UCHAR_ID_CONTINUE),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ isArgNumeric(TRUE),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ *this = that;
+}
+
+MessageFormat::~MessageFormat()
+{
+ int32_t idx;
+ for (idx = 0; idx < subformatCount; idx++) {
+ delete subformats[idx].format;
+ delete subformats[idx].argName;
+ }
+ uprv_free(subformats);
+ subformats = NULL;
+ subformatCount = subformatCapacity = 0;
+
+ uprv_free(argTypes);
+ argTypes = NULL;
+ argTypeCount = argTypeCapacity = 0;
+
+ uprv_free(formatAliases);
+
+ delete defaultNumberFormat;
+ delete defaultDateFormat;
+}
+
+//--------------------------------------------------------------------
+// Variable-size array management
+
+/**
+ * Allocate subformats[] to at least the given capacity and return
+ * TRUE if successful. If not, leave subformats[] unchanged.
+ *
+ * If subformats is NULL, allocate it. If it is not NULL, enlarge it
+ * if necessary to be at least as large as specified.
+ */
+UBool MessageFormat::allocateSubformats(int32_t capacity) {
+ if (subformats == NULL) {
+ subformats = (Subformat*) uprv_malloc(sizeof(*subformats) * capacity);
+ subformatCapacity = capacity;
+ subformatCount = 0;
+ if (subformats == NULL) {
+ subformatCapacity = 0;
+ return FALSE;
+ }
+ } else if (subformatCapacity < capacity) {
+ if (capacity < 2*subformatCapacity) {
+ capacity = 2*subformatCapacity;
+ }
+ Subformat* a = (Subformat*)
+ uprv_realloc(subformats, sizeof(*subformats) * capacity);
+ if (a == NULL) {
+ return FALSE; // request failed
+ }
+ subformats = a;
+ subformatCapacity = capacity;
+ }
+ return TRUE;
+}
+
+/**
+ * Allocate argTypes[] to at least the given capacity and return
+ * TRUE if successful. If not, leave argTypes[] unchanged.
+ *
+ * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
+ * if necessary to be at least as large as specified.
+ */
+UBool MessageFormat::allocateArgTypes(int32_t capacity) {
+ if (argTypes == NULL) {
+ argTypes = (Formattable::Type*) uprv_malloc(sizeof(*argTypes) * capacity);
+ argTypeCount = 0;
+ argTypeCapacity = capacity;
+ if (argTypes == NULL) {
+ argTypeCapacity = 0;
+ return FALSE;
+ }
+ for (int32_t i=0; i<capacity; ++i) {
+ argTypes[i] = Formattable::kString;
+ }
+ } else if (argTypeCapacity < capacity) {
+ if (capacity < 2*argTypeCapacity) {
+ capacity = 2*argTypeCapacity;
+ }
+ Formattable::Type* a = (Formattable::Type*)
+ uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
+ if (a == NULL) {
+ return FALSE; // request failed
+ }
+ for (int32_t i=argTypeCapacity; i<capacity; ++i) {
+ a[i] = Formattable::kString;
+ }
+ argTypes = a;
+ argTypeCapacity = capacity;
+ }
+ return TRUE;
+}
+
+// -------------------------------------
+// assignment operator
+
+const MessageFormat&
+MessageFormat::operator=(const MessageFormat& that)
+{
+ // Reallocate the arrays BEFORE changing this object
+ if (this != &that &&
+ allocateSubformats(that.subformatCount) &&
+ allocateArgTypes(that.argTypeCount)) {
+
+ // Calls the super class for assignment first.
+ Format::operator=(that);
+
+ fPattern = that.fPattern;
+ setLocale(that.fLocale);
+ isArgNumeric = that.isArgNumeric;
+ int32_t j;
+ for (j=0; j<subformatCount; ++j) {
+ delete subformats[j].format;
+ }
+ subformatCount = 0;
+
+ for (j=0; j<that.subformatCount; ++j) {
+ // Subformat::operator= does NOT delete this.format
+ subformats[j] = that.subformats[j];
+ }
+ subformatCount = that.subformatCount;
+
+ for (j=0; j<that.argTypeCount; ++j) {
+ argTypes[j] = that.argTypes[j];
+ }
+ argTypeCount = that.argTypeCount;
+ }
+ return *this;
+}
+
+UBool
+MessageFormat::operator==(const Format& rhs) const
+{
+ if (this == &rhs) return TRUE;
+
+ MessageFormat& that = (MessageFormat&)rhs;
+
+ // Check class ID before checking MessageFormat members
+ if (!Format::operator==(rhs) ||
+ fPattern != that.fPattern ||
+ fLocale != that.fLocale ||
+ isArgNumeric != that.isArgNumeric) {
+ return FALSE;
+ }
+
+ int32_t j;
+ for (j=0; j<subformatCount; ++j) {
+ if (subformats[j] != that.subformats[j]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// -------------------------------------
+// Creates a copy of this MessageFormat, the caller owns the copy.
+
+Format*
+MessageFormat::clone() const
+{
+ return new MessageFormat(*this);
+}
+
+// -------------------------------------
+// Sets the locale of this MessageFormat object to theLocale.
+
+void
+MessageFormat::setLocale(const Locale& theLocale)
+{
+ if (fLocale != theLocale) {
+ delete defaultNumberFormat;
+ defaultNumberFormat = NULL;
+ delete defaultDateFormat;
+ defaultDateFormat = NULL;
+ }
+ fLocale = theLocale;
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+// -------------------------------------
+// Gets the locale of this MessageFormat object.
+
+const Locale&
+MessageFormat::getLocale() const
+{
+ return fLocale;
+}
+
+
+
+
+void
+MessageFormat::applyPattern(const UnicodeString& newPattern,
+ UErrorCode& status)
+{
+ UParseError parseError;
+ applyPattern(newPattern,parseError,status);
+}
+
+
+// -------------------------------------
+// Applies the new pattern and returns an error if the pattern
+// is not correct.
+void
+MessageFormat::applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& ec)
+{
+ if(U_FAILURE(ec)) {
+ return;
+ }
+ // The pattern is broken up into segments. Each time a subformat
+ // is encountered, 4 segments are recorded. For example, consider
+ // the pattern:
+ // "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}."
+ // The first set of segments is:
+ // segments[0] = "There "
+ // segments[1] = "0"
+ // segments[2] = "choice"
+ // segments[3] = "0.0#are no files|1.0#is one file|1.0<are {0, number} files"
+
+ // During parsing, the plain text is accumulated into segments[0].
+ // Segments 1..3 are used to parse each subpattern. Each time a
+ // subpattern is parsed, it creates a format object that is stored
+ // in the subformats array, together with an offset and argument
+ // number. The offset into the plain text stored in
+ // segments[0].
+
+ // Quotes in segment 0 are handled normally. They are removed.
+ // Quotes may not occur in segments 1 or 2.
+ // Quotes in segment 3 are parsed and _copied_. This makes
+ // subformat patterns work, e.g., {1,number,'#'.##} passes
+ // the pattern "'#'.##" to DecimalFormat.
+
+ UnicodeString segments[4];
+ int32_t part = 0; // segment we are in, 0..3
+ // Record the highest argument number in the pattern. (In the
+ // subpattern {3,number} the argument number is 3.)
+ int32_t formatNumber = 0;
+ UBool inQuote = FALSE;
+ int32_t braceStack = 0;
+ // Clear error struct
+ parseError.offset = -1;
+ parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
+ int32_t patLen = pattern.length();
+ int32_t i;
+
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ subformatCount = 0;
+ argTypeCount = 0;
+
+ for (i=0; i<patLen; ++i) {
+ UChar ch = pattern[i];
+ if (part == 0) {
+ // In segment 0, recognize and remove quotes
+ if (ch == SINGLE_QUOTE) {
+ if (i+1 < patLen && pattern[i+1] == SINGLE_QUOTE) {
+ segments[0] += ch;
+ ++i;
+ } else {
+ inQuote = !inQuote;
+ }
+ } else if (ch == LEFT_CURLY_BRACE && !inQuote) {
+ // The only way we get from segment 0 to 1 is via an
+ // unquoted '{'.
+ part = 1;
+ } else {
+ segments[0] += ch;
+ }
+ } else if (inQuote) {
+ // In segments 1..3, recognize quoted matter, and copy it
+ // into the segment, together with the quotes. This takes
+ // care of '' as well.
+ segments[part] += ch;
+ if (ch == SINGLE_QUOTE) {
+ inQuote = FALSE;
+ }
+ } else {
+ // We have an unquoted character in segment 1..3
+ switch (ch) {
+ case COMMA:
+ // Commas bump us to the next segment, except for segment 3,
+ // which can contain commas. See example above.
+ if (part < 3)
+ part += 1;
+ else
+ segments[3] += ch;
+ break;
+ case LEFT_CURLY_BRACE:
+ // Handle '{' within segment 3. The initial '{'
+ // before segment 1 is handled above.
+ if (part != 3) {
+ ec = U_PATTERN_SYNTAX_ERROR;
+ goto SYNTAX_ERROR;
+ }
+ ++braceStack;
+ segments[part] += ch;
+ break;
+ case RIGHT_CURLY_BRACE:
+ if (braceStack == 0) {
+ makeFormat(formatNumber, segments, parseError,ec);
+ if (U_FAILURE(ec)){
+ goto SYNTAX_ERROR;
+ }
+ formatNumber++;
+
+ segments[1].remove();
+ segments[2].remove();
+ segments[3].remove();
+ part = 0;
+ } else {
+ --braceStack;
+ segments[part] += ch;
+ }
+ break;
+ case SINGLE_QUOTE:
+ inQuote = TRUE;
+ // fall through (copy quote chars in segments 1..3)
+ default:
+ segments[part] += ch;
+ break;
+ }
+ }
+ }
+ if (braceStack != 0 || part != 0) {
+ // Unmatched braces in the pattern
+ ec = U_UNMATCHED_BRACES;
+ goto SYNTAX_ERROR;
+ }
+ fPattern = segments[0];
+ return;
+
+ SYNTAX_ERROR:
+ syntaxError(pattern, i, parseError);
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ argTypeCount = subformatCount = 0;
+}
+// -------------------------------------
+// Converts this MessageFormat instance to a pattern.
+
+UnicodeString&
+MessageFormat::toPattern(UnicodeString& appendTo) const {
+ // later, make this more extensible
+ int32_t lastOffset = 0;
+ int32_t i;
+ for (i=0; i<subformatCount; ++i) {
+ copyAndFixQuotes(fPattern, lastOffset, subformats[i].offset, appendTo);
+ lastOffset = subformats[i].offset;
+ appendTo += LEFT_CURLY_BRACE;
+ if (isArgNumeric) {
+ itos(subformats[i].argNum, appendTo);
+ }
+ else {
+ appendTo += *subformats[i].argName;
+ }
+ Format* fmt = subformats[i].format;
+ DecimalFormat* decfmt;
+ SimpleDateFormat* sdtfmt;
+ ChoiceFormat* chcfmt;
+ PluralFormat* plfmt;
+ SelectFormat* selfmt;
+ if (fmt == NULL) {
+ // do nothing, string format
+ }
+ else if ((decfmt = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
+ UErrorCode ec = U_ZERO_ERROR;
+ NumberFormat& formatAlias = *decfmt;
+ NumberFormat *defaultTemplate = NumberFormat::createInstance(fLocale, ec);
+ NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, ec);
+ NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, ec);
+ NumberFormat *integerTemplate = createIntegerFormat(fLocale, ec);
+
+ appendTo += COMMA;
+ appendTo += ID_NUMBER;
+ if (formatAlias != *defaultTemplate) {
+ appendTo += COMMA;
+ if (formatAlias == *currencyTemplate) {
+ appendTo += ID_CURRENCY;
+ }
+ else if (formatAlias == *percentTemplate) {
+ appendTo += ID_PERCENT;
+ }
+ else if (formatAlias == *integerTemplate) {
+ appendTo += ID_INTEGER;
+ }
+ else {
+ UnicodeString buffer;
+ appendTo += decfmt->toPattern(buffer);
+ }
+ }
+
+ delete defaultTemplate;
+ delete currencyTemplate;
+ delete percentTemplate;
+ delete integerTemplate;
+ }
+ else if ((sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt)) != NULL) {
+ DateFormat& formatAlias = *sdtfmt;
+ DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
+ DateFormat *shortDateTemplate = DateFormat::createDateInstance(DateFormat::kShort, fLocale);
+ DateFormat *longDateTemplate = DateFormat::createDateInstance(DateFormat::kLong, fLocale);
+ DateFormat *fullDateTemplate = DateFormat::createDateInstance(DateFormat::kFull, fLocale);
+ DateFormat *defaultTimeTemplate = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
+ DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
+ DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
+ DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
+
+
+ appendTo += COMMA;
+ if (formatAlias == *defaultDateTemplate) {
+ appendTo += ID_DATE;
+ }
+ else if (formatAlias == *shortDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_SHORT;
+ }
+ else if (formatAlias == *defaultDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_MEDIUM;
+ }
+ else if (formatAlias == *longDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_LONG;
+ }
+ else if (formatAlias == *fullDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_FULL;
+ }
+ else if (formatAlias == *defaultTimeTemplate) {
+ appendTo += ID_TIME;
+ }
+ else if (formatAlias == *shortTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_SHORT;
+ }
+ else if (formatAlias == *defaultTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_MEDIUM;
+ }
+ else if (formatAlias == *longTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_LONG;
+ }
+ else if (formatAlias == *fullTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_FULL;
+ }
+ else {
+ UnicodeString buffer;
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += sdtfmt->toPattern(buffer);
+ }
+
+ delete defaultDateTemplate;
+ delete shortDateTemplate;
+ delete longDateTemplate;
+ delete fullDateTemplate;
+ delete defaultTimeTemplate;
+ delete shortTimeTemplate;
+ delete longTimeTemplate;
+ delete fullTimeTemplate;
+ // {sfb} there should be a more efficient way to do this!
+ }
+ else if ((chcfmt = dynamic_cast<ChoiceFormat*>(fmt)) != NULL) {
+ UnicodeString buffer;
+ appendTo += COMMA;
+ appendTo += ID_CHOICE;
+ appendTo += COMMA;
+ appendTo += ((ChoiceFormat*)fmt)->toPattern(buffer);
+ }
+ else if ((plfmt = dynamic_cast<PluralFormat*>(fmt)) != NULL) {
+ UnicodeString buffer;
+ appendTo += plfmt->toPattern(buffer);
+ }
+ else if ((selfmt = dynamic_cast<SelectFormat*>(fmt)) != NULL) {
+ UnicodeString buffer;
+ appendTo += ((SelectFormat*)fmt)->toPattern(buffer);
+ }
+ else {
+ //appendTo += ", unknown";
+ }
+ appendTo += RIGHT_CURLY_BRACE;
+ }
+ copyAndFixQuotes(fPattern, lastOffset, fPattern.length(), appendTo);
+ return appendTo;
+}
+
+// -------------------------------------
+// Adopts the new formats array and updates the array count.
+// This MessageFormat instance owns the new formats.
+
+void
+MessageFormat::adoptFormats(Format** newFormats,
+ int32_t count) {
+ if (newFormats == NULL || count < 0) {
+ return;
+ }
+
+ int32_t i;
+ if (allocateSubformats(count)) {
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ for (i=0; i<count; ++i) {
+ subformats[i].format = newFormats[i];
+ }
+ subformatCount = count;
+ } else {
+ // An adopt method must always take ownership. Delete
+ // the incoming format objects and return unchanged.
+ for (i=0; i<count; ++i) {
+ delete newFormats[i];
+ }
+ }
+
+ // TODO: What about the .offset and .argNum fields?
+}
+
+// -------------------------------------
+// Sets the new formats array and updates the array count.
+// This MessageFormat instance maks a copy of the new formats.
+
+void
+MessageFormat::setFormats(const Format** newFormats,
+ int32_t count) {
+ if (newFormats == NULL || count < 0) {
+ return;
+ }
+
+ if (allocateSubformats(count)) {
+ int32_t i;
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ subformatCount = 0;
+
+ for (i=0; i<count; ++i) {
+ subformats[i].format = newFormats[i] ? newFormats[i]->clone() : NULL;
+ }
+ subformatCount = count;
+ }
+
+ // TODO: What about the .offset and .arg fields?
+}
+
+// -------------------------------------
+// Adopt a single format by format number.
+// Do nothing if the format number is not less than the array count.
+
+void
+MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
+ if (n < 0 || n >= subformatCount) {
+ delete newFormat;
+ } else {
+ delete subformats[n].format;
+ subformats[n].format = newFormat;
+ }
+}
+
+// -------------------------------------
+// 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) {
+ if (isArgNumeric ) {
+ int32_t argumentNumber = stou(formatName);
+ if (argumentNumber<0) {
+ status = U_ARGUMENT_TYPE_MISMATCH;
+ return;
+ }
+ adoptFormat(argumentNumber, formatToAdopt);
+ return;
+ }
+ for (int32_t i=0; i<subformatCount; ++i) {
+ if (formatName==*subformats[i].argName) {
+ delete subformats[i].format;
+ if ( formatToAdopt== NULL) {
+ // This should never happen -- but we'll be nice if it does
+ subformats[i].format = NULL;
+ } else {
+ subformats[i].format = formatToAdopt;
+ }
+ }
+ }
+}
+
+// -------------------------------------
+// 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 && n < subformatCount) {
+ delete subformats[n].format;
+ if (&newFormat == NULL) {
+ // This should never happen -- but we'll be nice if it does
+ subformats[n].format = NULL;
+ } else {
+ subformats[n].format = newFormat.clone();
+ }
+ }
+}
+
+// -------------------------------------
+// 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)) return NULL;
+
+ if (isArgNumeric ) {
+ int32_t argumentNumber = stou(formatName);
+ if (argumentNumber<0) {
+ status = U_ARGUMENT_TYPE_MISMATCH;
+ return NULL;
+ }
+ if (argumentNumber < 0 || argumentNumber >= subformatCount) {
+ return subformats[argumentNumber].format;
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ for (int32_t i=0; i<subformatCount; ++i) {
+ if (formatName==*subformats[i].argName)
+ {
+ return subformats[i].format;
+ }
+ }
+ 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 (isArgNumeric) {
+ status = U_ARGUMENT_TYPE_MISMATCH;
+ return;
+ }
+ for (int32_t i=0; i<subformatCount; ++i) {
+ if (formatName==*subformats[i].argName)
+ {
+ delete subformats[i].format;
+ if (&newFormat == NULL) {
+ // This should never happen -- but we'll be nice if it does
+ subformats[i].format = NULL;
+ } else {
+ subformats[i].format = newFormat.clone();
+ }
+ break;
+ }
+ }
+}
+
+// -------------------------------------
+// Gets the format array.
+
+const Format**
+MessageFormat::getFormats(int32_t& cnt) const
+{
+ // This old API returns an array (which we hold) of Format*
+ // pointers. The array is valid up to the next call to any
+ // method on this object. We construct and resize an array
+ // on demand that contains aliases to the subformats[i].format
+ // pointers.
+ MessageFormat* t = (MessageFormat*) this;
+ cnt = 0;
+ if (formatAliases == NULL) {
+ t->formatAliasesCapacity = (subformatCount<10) ? 10 : subformatCount;
+ Format** a = (Format**)
+ uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
+ if (a == NULL) {
+ return NULL;
+ }
+ t->formatAliases = a;
+ } else if (subformatCount > formatAliasesCapacity) {
+ Format** a = (Format**)
+ uprv_realloc(formatAliases, sizeof(Format*) * subformatCount);
+ if (a == NULL) {
+ return NULL;
+ }
+ t->formatAliases = a;
+ t->formatAliasesCapacity = subformatCount;
+ }
+ for (int32_t i=0; i<subformatCount; ++i) {
+ t->formatAliases[i] = subformats[i].format;
+ }
+ cnt = subformatCount;
+ return (const Format**)formatAliases;
+}
+
+
+StringEnumeration*
+MessageFormat::getFormatNames(UErrorCode& status) {
+ if (U_FAILURE(status)) return NULL;
+
+ if (isArgNumeric) {
+ status = U_ARGUMENT_TYPE_MISMATCH;
+ return NULL;
+ }
+ UVector *fFormatNames = new UVector(status);
+ if (U_FAILURE(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ for (int32_t i=0; i<subformatCount; ++i) {
+ fFormatNames->addElement(new UnicodeString(*subformats[i].argName), 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
+{
+ if (U_FAILURE(success))
+ return appendTo;
+
+ return format(source, cnt, appendTo, ignore, 0, success);
+}
+
+// -------------------------------------
+// Internally creates a MessageFormat instance based on the
+// pattern and formats the arguments Formattable array and
+// copy into the appendTo buffer.
+
+UnicodeString&
+MessageFormat::format( const UnicodeString& pattern,
+ const Formattable* arguments,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ UErrorCode& success)
+{
+ MessageFormat temp(pattern, success);
+ FieldPosition ignore(0);
+ temp.format(arguments, cnt, appendTo, ignore, success);
+ return appendTo;
+}
+
+// -------------------------------------
+// Formats the source Formattable object and copy into the
+// appendTo buffer. The Formattable object must be an array
+// of Formattable instances, returns error otherwise.
+
+UnicodeString&
+MessageFormat::format(const Formattable& source,
+ UnicodeString& appendTo,
+ FieldPosition& ignore,
+ UErrorCode& success) const
+{
+ int32_t cnt;
+
+ if (U_FAILURE(success))
+ return appendTo;
+ if (source.getType() != Formattable::kArray) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+ const Formattable* tmpPtr = source.getArray(cnt);
+
+ return format(tmpPtr, cnt, appendTo, ignore, 0, success);
+}
+
+
+UnicodeString&
+MessageFormat::format(const UnicodeString* argumentNames,
+ const Formattable* arguments,
+ int32_t count,
+ UnicodeString& appendTo,
+ UErrorCode& success) const {
+ FieldPosition ignore(0);
+ return format(arguments, argumentNames, count, appendTo, ignore, 0, success);
+}
+
+UnicodeString&
+MessageFormat::format(const Formattable* arguments,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& status,
+ int32_t recursionProtection,
+ UErrorCode& success) const
+{
+ return format(arguments, NULL, cnt, appendTo, status, recursionProtection, success);
+}
+
+// -------------------------------------
+// Formats the arguments Formattable array and copy into the appendTo buffer.
+// Ignore the FieldPosition result for error checking.
+
+UnicodeString&
+MessageFormat::format(const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& status,
+ int32_t recursionProtection,
+ UErrorCode& success) const
+{
+ int32_t lastOffset = 0;
+ int32_t argumentNumber=0;
+ if (cnt < 0 || (cnt && arguments == NULL)) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ if ( !isArgNumeric && argumentNames== NULL ) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ const Formattable *obj=NULL;
+ for (int32_t i=0; i<subformatCount; ++i) {
+ // Append the prefix of current format element.
+ appendTo.append(fPattern, lastOffset, subformats[i].offset - lastOffset);
+ lastOffset = subformats[i].offset;
+ obj = NULL;
+ if (isArgNumeric) {
+ argumentNumber = subformats[i].argNum;
+
+ // Checks the scope of the argument number.
+ if (argumentNumber >= cnt) {
+ appendTo += LEFT_CURLY_BRACE;
+ itos(argumentNumber, appendTo);
+ appendTo += RIGHT_CURLY_BRACE;
+ continue;
+ }
+ obj = arguments+argumentNumber;
+ }
+ else {
+ for (int32_t j=0; j<cnt; ++j) {
+ if (argumentNames[j]== *subformats[i].argName ) {
+ obj = arguments+j;
+ break;
+ }
+ }
+ if (obj == NULL ) {
+ appendTo += LEFT_CURLY_BRACE;
+ appendTo += *subformats[i].argName;
+ appendTo += RIGHT_CURLY_BRACE;
+ continue;
+
+ }
+ }
+ Formattable::Type type = obj->getType();
+
+ // Recursively calling the format process only if the current
+ // format argument refers to either of the following:
+ // a ChoiceFormat object, a PluralFormat object, a SelectFormat object.
+ Format* fmt = subformats[i].format;
+ if (fmt != NULL) {
+ UnicodeString argNum;
+ fmt->format(*obj, argNum, success);
+
+ // Needs to reprocess the ChoiceFormat and PluralFormat and SelectFormat option by using the
+ // MessageFormat pattern application.
+ if ((dynamic_cast<ChoiceFormat*>(fmt) != NULL ||
+ dynamic_cast<PluralFormat*>(fmt) != NULL ||
+ dynamic_cast<SelectFormat*>(fmt) != NULL) &&
+ argNum.indexOf(LEFT_CURLY_BRACE) >= 0
+ ) {
+ MessageFormat temp(argNum, fLocale, success);
+ // TODO: Implement recursion protection
+ if ( isArgNumeric ) {
+ temp.format(arguments, NULL, cnt, appendTo, status, recursionProtection, success);
+ }
+ else {
+ temp.format(arguments, argumentNames, cnt, appendTo, status, recursionProtection, success);
+ }
+ if (U_FAILURE(success)) {
+ return appendTo;
+ }
+ }
+ else {
+ appendTo += argNum;
+ }
+ }
+ // If the obj data type is a number, use a NumberFormat instance.
+ else if ((type == Formattable::kDouble) ||
+ (type == Formattable::kLong) ||
+ (type == Formattable::kInt64)) {
+
+ const NumberFormat* nf = getDefaultNumberFormat(success);
+ if (nf == NULL) {
+ return appendTo;
+ }
+ if (type == Formattable::kDouble) {
+ nf->format(obj->getDouble(), appendTo);
+ } else if (type == Formattable::kLong) {
+ nf->format(obj->getLong(), appendTo);
+ } else {
+ nf->format(obj->getInt64(), appendTo);
+ }
+ }
+ // If the obj data type is a Date instance, use a DateFormat instance.
+ else if (type == Formattable::kDate) {
+ const DateFormat* df = getDefaultDateFormat(success);
+ if (df == NULL) {
+ return appendTo;
+ }
+ df->format(obj->getDate(), appendTo);
+ }
+ else if (type == Formattable::kString) {
+ appendTo += obj->getString();
+ }
+ else {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+ }
+ // Appends the rest of the pattern characters after the real last offset.
+ appendTo.append(fPattern, lastOffset, 0x7fffffff);
+ return appendTo;
+}
+
+
+// -------------------------------------
+// Parses the source pattern and returns the Formattable objects array,
+// the array count and the ending parse position. The caller of this method
+// owns the array.
+
+Formattable*
+MessageFormat::parse(const UnicodeString& source,
+ ParsePosition& pos,
+ int32_t& count) const
+{
+ // Allocate at least one element. Allocating an array of length
+ // zero causes problems on some platforms (e.g. Win32).
+ Formattable *resultArray = new Formattable[argTypeCount ? argTypeCount : 1];
+ int32_t patternOffset = 0;
+ int32_t sourceOffset = pos.getIndex();
+ ParsePosition tempPos(0);
+ count = 0; // {sfb} reset to zero
+ int32_t len;
+ // If resultArray could not be created, exit out.
+ // Avoid crossing initialization of variables above.
+ if (resultArray == NULL) {
+ goto PARSE_ERROR;
+ }
+ for (int32_t i = 0; i < subformatCount; ++i) {
+ // match up to format
+ len = subformats[i].offset - patternOffset;
+ if (len == 0 ||
+ fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
+ sourceOffset += len;
+ patternOffset += len;
+ }
+ else {
+ goto PARSE_ERROR;
+ }
+
+ // now use format
+ Format* fmt = subformats[i].format;
+ int32_t argNum = subformats[i].argNum;
+ if (fmt == NULL) { // string format
+ // if at end, use longest possible match
+ // otherwise uses first match to intervening string
+ // does NOT recursively try all possibilities
+ int32_t tempLength = (i+1<subformatCount) ?
+ subformats[i+1].offset : fPattern.length();
+
+ int32_t next;
+ if (patternOffset >= tempLength) {
+ next = source.length();
+ }
+ else {
+ UnicodeString buffer;
+ fPattern.extract(patternOffset,tempLength - patternOffset, buffer);
+ next = source.indexOf(buffer, sourceOffset);
+ }
+
+ if (next < 0) {
+ goto PARSE_ERROR;
+ }
+ else {
+ UnicodeString buffer;
+ source.extract(sourceOffset,next - sourceOffset, buffer);
+ UnicodeString strValue = buffer;
+ UnicodeString temp(LEFT_CURLY_BRACE);
+ // {sfb} check this later
+ if (isArgNumeric) {
+ itos(argNum, temp);
+ }
+ else {
+ temp+=(*subformats[i].argName);
+ }
+ temp += RIGHT_CURLY_BRACE;
+ if (strValue != temp) {
+ source.extract(sourceOffset,next - sourceOffset, buffer);
+ resultArray[argNum].setString(buffer);
+ // {sfb} not sure about this
+ if ((argNum + 1) > count) {
+ count = argNum + 1;
+ }
+ }
+ sourceOffset = next;
+ }
+ }
+ else {
+ tempPos.setIndex(sourceOffset);
+ fmt->parseObject(source, resultArray[argNum], tempPos);
+ if (tempPos.getIndex() == sourceOffset) {
+ goto PARSE_ERROR;
+ }
+
+ if ((argNum + 1) > count) {
+ count = argNum + 1;
+ }
+ sourceOffset = tempPos.getIndex(); // update
+ }
+ }
+ len = fPattern.length() - patternOffset;
+ if (len == 0 ||
+ fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
+ pos.setIndex(sourceOffset + len);
+ return resultArray;
+ }
+ // else fall through...
+
+ PARSE_ERROR:
+ pos.setErrorIndex(sourceOffset);
+ delete [] resultArray;
+ count = 0;
+ return NULL; // leave index as is to signal error
+}
+
+// -------------------------------------
+// Parses the source string and returns the array of
+// Formattable objects and the array count. The caller
+// owns the returned array.
+
+Formattable*
+MessageFormat::parse(const UnicodeString& source,
+ int32_t& cnt,
+ UErrorCode& success) const
+{
+ if (!isArgNumeric ) {
+ 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;
+}
+
+/**
+ * Reads the segments[] array (see applyPattern()) and parses the
+ * segments[1..3] into a Format* object. Stores the format object in
+ * the subformats[] array. Updates the argTypes[] array type
+ * information for the corresponding argument.
+ *
+ * @param formatNumber index into subformats[] for this format
+ * @param segments array of strings with the parsed pattern segments
+ * @param parseError parse error data (output param)
+ * @param ec error code
+ */
+void
+MessageFormat::makeFormat(int32_t formatNumber,
+ UnicodeString* segments,
+ UParseError& parseError,
+ UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ // Parse the argument number
+ int32_t argumentNumber = stou(segments[1]); // always unlocalized!
+ UnicodeString argumentName;
+ if (argumentNumber < 0) {
+ if ( (isArgNumeric==TRUE) && (formatNumber !=0) ) {
+ ec = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ isArgNumeric = FALSE;
+ argumentNumber=formatNumber;
+ }
+ if (!isArgNumeric) {
+ if ( !isLegalArgName(segments[1]) ) {
+ ec = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ argumentName = segments[1];
+ }
+
+ // Parse the format, recording the argument type and creating a
+ // new Format object (except for string arguments).
+ Formattable::Type argType;
+ Format *fmt = NULL;
+ int32_t typeID, styleID;
+ DateFormat::EStyle style;
+ UnicodeString unquotedPattern, quotedPattern;
+ UBool inQuote = FALSE;
+
+ switch (typeID = findKeyword(segments[2], TYPE_IDS)) {
+
+ case 0: // string
+ argType = Formattable::kString;
+ break;
+
+ case 1: // number
+ argType = Formattable::kDouble;
+
+ switch (findKeyword(segments[3], NUMBER_STYLE_IDS)) {
+ case 0: // default
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ break;
+ case 1: // currency
+ fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
+ break;
+ case 2: // percent
+ fmt = NumberFormat::createPercentInstance(fLocale, ec);
+ break;
+ case 3: // integer
+ argType = Formattable::kLong;
+ fmt = createIntegerFormat(fLocale, ec);
+ break;
+ default: // pattern
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ if (fmt) {
+ DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt);
+ if (decfmt != NULL) {
+ decfmt->applyPattern(segments[3],parseError,ec);
+ }
+ }
+ break;
+ }
+ break;
+
+ case 2: // date
+ case 3: // time
+ argType = Formattable::kDate;
+ styleID = findKeyword(segments[3], DATE_STYLE_IDS);
+ style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
+
+ if (typeID == 2) {
+ fmt = DateFormat::createDateInstance(style, fLocale);
+ } else {
+ fmt = DateFormat::createTimeInstance(style, fLocale);
+ }
+
+ if (styleID < 0 && fmt != NULL) {
+ SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
+ if (sdtfmt != NULL) {
+ sdtfmt->applyPattern(segments[3]);
+ }
+ }
+ break;
+
+ case 4: // choice
+ argType = Formattable::kDouble;
+
+ fmt = new ChoiceFormat(segments[3], parseError, ec);
+ break;
+
+ case 5: // spellout
+ argType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_SPELLOUT, fLocale, segments[3], ec);
+ break;
+ case 6: // ordinal
+ argType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_ORDINAL, fLocale, segments[3], ec);
+ break;
+ case 7: // duration
+ argType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_DURATION, fLocale, segments[3], ec);
+ break;
+ case 8: // plural
+ case 9: // Select
+ if(typeID == 8)
+ argType = Formattable::kDouble;
+ else
+ argType = Formattable::kString;
+ quotedPattern = segments[3];
+ for (int32_t i = 0; i < quotedPattern.length(); ++i) {
+ UChar ch = quotedPattern.charAt(i);
+ if (ch == SINGLE_QUOTE) {
+ if (i+1 < quotedPattern.length() && quotedPattern.charAt(i+1)==SINGLE_QUOTE) {
+ unquotedPattern+=ch;
+ ++i;
+ }
+ else {
+ inQuote = !inQuote;
+ }
+ }
+ else {
+ unquotedPattern += ch;
+ }
+ }
+ if(typeID == 8)
+ fmt = new PluralFormat(fLocale, unquotedPattern, ec);
+ else
+ fmt = new SelectFormat(unquotedPattern, ec);
+ break;
+ default:
+ argType = Formattable::kString;
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+
+ if (fmt==NULL && argType!=Formattable::kString && U_SUCCESS(ec)) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (!allocateSubformats(formatNumber+1) ||
+ !allocateArgTypes(argumentNumber+1)) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (U_FAILURE(ec)) {
+ delete fmt;
+ return;
+ }
+
+ // Parse succeeded; record results in our arrays
+ subformats[formatNumber].format = fmt;
+ subformats[formatNumber].offset = segments[0].length();
+ if (isArgNumeric) {
+ subformats[formatNumber].argName = NULL;
+ subformats[formatNumber].argNum = argumentNumber;
+ }
+ else {
+ subformats[formatNumber].argName = new UnicodeString(argumentName);
+ subformats[formatNumber].argNum = -1;
+ }
+ subformatCount = formatNumber+1;
+
+ // Careful here: argumentNumber may in general arrive out of
+ // sequence, e.g., "There was {2} on {0,date} (see {1,number})."
+ argTypes[argumentNumber] = argType;
+ if (argumentNumber+1 > argTypeCount) {
+ argTypeCount = argumentNumber+1;
+ }
+}
+
+// -------------------------------------
+// Finds the string, s, in the string array, list.
+int32_t MessageFormat::findKeyword(const UnicodeString& s,
+ const UChar * const *list)
+{
+ if (s.length() == 0)
+ return 0; // default
+
+ UnicodeString buffer = s;
+ // Trims the space characters and turns all characters
+ // in s to lower case.
+ buffer.trim().toLower("");
+ for (int32_t i = 0; list[i]; ++i) {
+ if (!buffer.compare(list[i], u_strlen(list[i]))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// -------------------------------------
+// Checks the range of the source text to quote the special
+// characters, { and ' and copy to target buffer.
+
+void
+MessageFormat::copyAndFixQuotes(const UnicodeString& source,
+ int32_t start,
+ int32_t end,
+ UnicodeString& appendTo)
+{
+ UBool gotLB = FALSE;
+
+ for (int32_t i = start; i < end; ++i) {
+ UChar ch = source[i];
+ if (ch == LEFT_CURLY_BRACE) {
+ appendTo += SINGLE_QUOTE;
+ appendTo += LEFT_CURLY_BRACE;
+ appendTo += SINGLE_QUOTE;
+ gotLB = TRUE;
+ }
+ else if (ch == RIGHT_CURLY_BRACE) {
+ if(gotLB) {
+ appendTo += RIGHT_CURLY_BRACE;
+ gotLB = FALSE;
+ }
+ else {
+ // orig code.
+ appendTo += SINGLE_QUOTE;
+ appendTo += RIGHT_CURLY_BRACE;
+ appendTo += SINGLE_QUOTE;
+ }
+ }
+ else if (ch == SINGLE_QUOTE) {
+ appendTo += SINGLE_QUOTE;
+ appendTo += SINGLE_QUOTE;
+ }
+ else {
+ appendTo += ch;
+ }
+ }
+}
+
+/**
+ * Convenience method that ought to be in NumberFormat
+ */
+NumberFormat*
+MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
+ NumberFormat *temp = NumberFormat::createInstance(locale, status);
+ 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 !isArgNumeric;
+}
+
+UBool
+MessageFormat::isLegalArgName(const UnicodeString& argName) const {
+ if(!u_hasBinaryProperty(argName.charAt(0), idStart)) {
+ return FALSE;
+ }
+ for (int32_t i=1; i<argName.length(); ++i) {
+ if(!u_hasBinaryProperty(argName.charAt(i), idContinue)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+int32_t
+MessageFormat::getArgTypeCount() const {
+ return argTypeCount;
+}
+
+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() {
+ UnicodeString *s;
+ for (int32_t i=0; i<fFormatNames->size(); ++i) {
+ if ((s=(UnicodeString *)fFormatNames->elementAt(i))!=NULL) {
+ delete s;
+ }
+ }
+ delete fFormatNames;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/msgfmt_impl.h b/Build/source/libs/icu/icu-4.6/i18n/msgfmt_impl.h
new file mode 100644
index 00000000000..699dc37002c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/name2uni.cpp b/Build/source/libs/icu/icu-4.6/i18n/name2uni.cpp
new file mode 100644
index 00000000000..4c2e9d28e23
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/name2uni.cpp
@@ -0,0 +1,254 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2008, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 06/07/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifilt.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "name2uni.h"
+#include "cmemory.h"
+#include "uprops.h"
+#include "uinvchar.h"
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NameUnicodeTransliterator)
+
+static const UChar OPEN[] = {92,78,126,123,126,0}; // "\N~{~"
+static const UChar OPEN_DELIM = 92; // '\\' first char of OPEN
+static const UChar CLOSE_DELIM = 125; // '}'
+static const UChar SPACE = 32; // ' '
+
+U_CDECL_BEGIN
+
+// USetAdder implementation
+// Does not use uset.h to reduce code dependencies
+static void U_CALLCONV
+_set_add(USet *set, UChar32 c) {
+ uset_add(set, c);
+}
+
+// These functions aren't used.
+/*static void U_CALLCONV
+_set_addRange(USet *set, UChar32 start, UChar32 end) {
+ ((UnicodeSet *)set)->add(start, end);
+}
+
+static void U_CALLCONV
+_set_addString(USet *set, const UChar *str, int32_t length) {
+ ((UnicodeSet *)set)->add(UnicodeString((UBool)(length<0), str, length));
+}*/
+
+U_CDECL_END
+
+/**
+ * Constructs a transliterator with the default delimiters '{' and
+ * '}'.
+ */
+NameUnicodeTransliterator::NameUnicodeTransliterator(UnicodeFilter* adoptedFilter) :
+ Transliterator(UNICODE_STRING("Name-Any", 8), adoptedFilter) {
+
+ UnicodeSet *legalPtr = &legal;
+ // Get the legal character set
+ USetAdder sa = {
+ (USet *)legalPtr, // USet* == UnicodeSet*
+ _set_add,
+ NULL, // Don't need _set_addRange
+ NULL, // Don't need _set_addString
+ NULL, // Don't need remove()
+ 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 (uprv_isRuleWhiteSpace(c)) {
+ // Ignore leading whitespace
+ if (name.length() > 0 &&
+ name.charAt(name.length()-1) != SPACE) {
+ name.append(SPACE);
+ // If we are too long then abort. maxLen includes
+ // temporary trailing space, so use '>'.
+ if (name.length() > maxLen) {
+ mode = 0;
+ }
+ }
+ break;
+ }
+
+ if (c == CLOSE_DELIM) {
+ int32_t len = name.length();
+
+ // Delete trailing space, if any
+ if (len > 0 &&
+ name.charAt(len-1) == SPACE) {
+ --len;
+ }
+
+ if (uprv_isInvariantUString(name.getBuffer(), len)) {
+ name.extract(0, len, cbuf, maxLen, US_INV);
+
+ UErrorCode status = U_ZERO_ERROR;
+ c = u_charFromName(U_EXTENDED_CHAR_NAME, cbuf, &status);
+ if (U_SUCCESS(status)) {
+ // Lookup succeeded
+
+ // assert(UTF_CHAR_LENGTH(CLOSE_DELIM) == 1);
+ cursor++; // advance over CLOSE_DELIM
+
+ str.truncate(0);
+ str.append(c);
+ text.handleReplaceBetween(openPos, cursor, str);
+
+ // Adjust indices for the change in the length of
+ // the string. Do not assume that str.length() ==
+ // 1, in case of surrogates.
+ int32_t delta = cursor - openPos - str.length();
+ cursor -= delta;
+ limit -= delta;
+ // assert(cursor == openPos + str.length());
+ }
+ }
+ // If the lookup failed, we leave things as-is and
+ // still switch to mode 0 and continue.
+ mode = 0;
+ openPos = -1; // close off candidate
+ continue; // *** reprocess char32At(cursor)
+ }
+
+ // Check if c is a legal char. We assume here that
+ // legal.contains(OPEN_DELIM) is FALSE, so when we abort a
+ // name, we don't have to go back to openPos+1.
+ if (legal.contains(c)) {
+ name.append(c);
+ // If we go past the longest possible name then abort.
+ // maxLen includes temporary trailing space, so use '>='.
+ if (name.length() >= maxLen) {
+ mode = 0;
+ }
+ }
+
+ // Invalid character
+ else {
+ --cursor; // Backup and reprocess this character
+ mode = 0;
+ }
+
+ break;
+ }
+
+ cursor += UTF_CHAR_LENGTH(c);
+ }
+
+ offsets.contextLimit += limit - offsets.limit;
+ offsets.limit = limit;
+ // In incremental mode, only advance the cursor up to the last
+ // open delimiter candidate.
+ offsets.start = (isIncremental && openPos >= 0) ? openPos : cursor;
+
+ uprv_free(cbuf);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/name2uni.h b/Build/source/libs/icu/icu-4.6/i18n/name2uni.h
new file mode 100644
index 00000000000..1324ec3e8d2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nfrlist.h b/Build/source/libs/icu/icu-4.6/i18n/nfrlist.h
new file mode 100644
index 00000000000..a33731d87ca
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/nfrlist.h
@@ -0,0 +1,97 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2008, 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.6/i18n/nfrs.cpp b/Build/source/libs/icu/icu-4.6/i18n/nfrs.cpp
new file mode 100644
index 00000000000..ef72ce38ccb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/nfrs.cpp
@@ -0,0 +1,946 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2008, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfrs.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#include "nfrs.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/uchar.h"
+#include "nfrule.h"
+#include "nfrlist.h"
+
+#ifdef RBNF_DEBUG
+#include "cmemory.h"
+#endif
+
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+#if 0
+// euclid's algorithm works with doubles
+// note, doubles only get us up to one quadrillion or so, which
+// isn't as much range as we get with longs. We probably still
+// want either 64-bit math, or BigInteger.
+
+static int64_t
+util_lcm(int64_t x, int64_t y)
+{
+ x.abs();
+ y.abs();
+
+ if (x == 0 || y == 0) {
+ return 0;
+ } else {
+ do {
+ if (x < y) {
+ int64_t t = x; x = y; y = t;
+ }
+ x -= y * (x/y);
+ } while (x != 0);
+
+ return y;
+ }
+}
+
+#else
+/**
+ * Calculates the least common multiple of x and y.
+ */
+static int64_t
+util_lcm(int64_t x, int64_t y)
+{
+ // binary gcd algorithm from Knuth, "The Art of Computer Programming,"
+ // vol. 2, 1st ed., pp. 298-299
+ int64_t x1 = x;
+ int64_t y1 = y;
+
+ int p2 = 0;
+ while ((x1 & 1) == 0 && (y1 & 1) == 0) {
+ ++p2;
+ x1 >>= 1;
+ y1 >>= 1;
+ }
+
+ int64_t t;
+ if ((x1 & 1) == 1) {
+ t = -y1;
+ } else {
+ t = x1;
+ }
+
+ while (t != 0) {
+ while ((t & 1) == 0) {
+ t = t >> 1;
+ }
+ if (t > 0) {
+ x1 = t;
+ } else {
+ y1 = -t;
+ }
+ t = x1 - y1;
+ }
+
+ int64_t gcd = x1 << p2;
+
+ // x * y == gcd(x, y) * lcm(x, y)
+ return x / gcd * y;
+}
+#endif
+
+static const UChar gPercent = 0x0025;
+static const UChar gColon = 0x003a;
+static const UChar gSemicolon = 0x003b;
+static const UChar gLineFeed = 0x000a;
+
+static const UChar gFourSpaces[] =
+{
+ 0x20, 0x20, 0x20, 0x20, 0
+}; /* " " */
+static const UChar gPercentPercent[] =
+{
+ 0x25, 0x25, 0
+}; /* "%%" */
+
+NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& status)
+ : name()
+ , rules(0)
+ , negativeNumberRule(NULL)
+ , fIsFractionRuleSet(FALSE)
+ , fIsPublic(FALSE)
+ , fRecursionCount(0)
+{
+ for (int i = 0; i < 3; ++i) {
+ fractionRules[i] = NULL;
+ }
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UnicodeString& description = descriptions[index]; // !!! make sure index is valid
+
+ if (description.length() == 0) {
+ // throw new IllegalArgumentException("Empty rule set description");
+ status = U_PARSE_ERROR;
+ return;
+ }
+
+ // if the description begins with a rule set name (the rule set
+ // name can be omitted in formatter descriptions that consist
+ // of only one rule set), copy it out into our "name" member
+ // and delete it from the description
+ if (description.charAt(0) == gPercent) {
+ int32_t pos = description.indexOf(gColon);
+ if (pos == -1) {
+ // throw new IllegalArgumentException("Rule set name doesn't end in colon");
+ status = U_PARSE_ERROR;
+ } else {
+ name.setTo(description, 0, pos);
+ while (pos < description.length() && uprv_isRuleWhiteSpace(description.charAt(++pos))) {
+ }
+ description.remove(0, pos);
+ }
+ } else {
+ name.setTo(UNICODE_STRING_SIMPLE("%default"));
+ }
+
+ if (description.length() == 0) {
+ // throw new IllegalArgumentException("Empty rule set description");
+ status = U_PARSE_ERROR;
+ }
+
+ fIsPublic = name.indexOf(gPercentPercent) != 0;
+
+ // all of the other members of NFRuleSet are initialized
+ // by parseRules()
+}
+
+void
+NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* owner, UErrorCode& status)
+{
+ // start by creating a Vector whose elements are Strings containing
+ // the descriptions of the rules (one rule per element). The rules
+ // are separated by semicolons (there's no escape facility: ALL
+ // semicolons are rule delimiters)
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // dlf - the original code kept a separate description array for no reason,
+ // so I got rid of it. The loop was too complex so I simplified it.
+
+ UnicodeString currentDescription;
+ int32_t oldP = 0;
+ while (oldP < description.length()) {
+ int32_t p = description.indexOf(gSemicolon, oldP);
+ if (p == -1) {
+ p = description.length();
+ }
+ currentDescription.setTo(description, oldP, p - oldP);
+ NFRule::makeRules(currentDescription, this, rules.last(), owner, rules, status);
+ oldP = p + 1;
+ }
+
+ // for rules that didn't specify a base value, their base values
+ // were initialized to 0. Make another pass through the list and
+ // set all those rules' base values. We also remove any special
+ // rules from the list and put them into their own member variables
+ int64_t defaultBaseValue = 0;
+
+ // (this isn't a for loop because we might be deleting items from
+ // the vector-- we want to make sure we only increment i when
+ // we _didn't_ delete aything from the vector)
+ uint32_t i = 0;
+ while (i < rules.size()) {
+ NFRule* rule = rules[i];
+
+ switch (rule->getType()) {
+ // if the rule's base value is 0, fill in a default
+ // base value (this will be 1 plus the preceding
+ // rule's base value for regular rule sets, and the
+ // same as the preceding rule's base value in fraction
+ // rule sets)
+ case NFRule::kNoBase:
+ rule->setBaseValue(defaultBaseValue, status);
+ if (!isFractionRuleSet()) {
+ ++defaultBaseValue;
+ }
+ ++i;
+ break;
+
+ // if it's the negative-number rule, copy it into its own
+ // data member and delete it from the list
+ case NFRule::kNegativeNumberRule:
+ negativeNumberRule = rules.remove(i);
+ break;
+
+ // if it's the improper fraction rule, copy it into the
+ // correct element of fractionRules
+ case NFRule::kImproperFractionRule:
+ fractionRules[0] = rules.remove(i);
+ break;
+
+ // if it's the proper fraction rule, copy it into the
+ // correct element of fractionRules
+ case NFRule::kProperFractionRule:
+ fractionRules[1] = rules.remove(i);
+ break;
+
+ // if it's the master rule, copy it into the
+ // correct element of fractionRules
+ case NFRule::kMasterRule:
+ fractionRules[2] = rules.remove(i);
+ break;
+
+ // if it's a regular rule that already knows its base value,
+ // check to make sure the rules are in order, and update
+ // the default base value for the next rule
+ default:
+ if (rule->getBaseValue() < defaultBaseValue) {
+ // throw new IllegalArgumentException("Rules are not in order");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ defaultBaseValue = rule->getBaseValue();
+ if (!isFractionRuleSet()) {
+ ++defaultBaseValue;
+ }
+ ++i;
+ break;
+ }
+ }
+}
+
+NFRuleSet::~NFRuleSet()
+{
+ delete negativeNumberRule;
+ delete fractionRules[0];
+ delete fractionRules[1];
+ delete fractionRules[2];
+}
+
+static UBool
+util_equalRules(const NFRule* rule1, const NFRule* rule2)
+{
+ if (rule1) {
+ if (rule2) {
+ return *rule1 == *rule2;
+ }
+ } else if (!rule2) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+NFRuleSet::operator==(const NFRuleSet& rhs) const
+{
+ if (rules.size() == rhs.rules.size() &&
+ fIsFractionRuleSet == rhs.fIsFractionRuleSet &&
+ name == rhs.name &&
+ util_equalRules(negativeNumberRule, rhs.negativeNumberRule) &&
+ util_equalRules(fractionRules[0], rhs.fractionRules[0]) &&
+ util_equalRules(fractionRules[1], rhs.fractionRules[1]) &&
+ util_equalRules(fractionRules[2], rhs.fractionRules[2])) {
+
+ for (uint32_t i = 0; i < rules.size(); ++i) {
+ if (*rules[i] != *rhs.rules[i]) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define RECURSION_LIMIT 50
+
+void
+NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos) const
+{
+ NFRule *rule = findNormalRule(number);
+ if (rule) { // else error, but can't report it
+ NFRuleSet* ncThis = (NFRuleSet*)this;
+ if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) {
+ // stop recursion
+ ncThis->fRecursionCount = 0;
+ } else {
+ rule->doFormat(number, toAppendTo, pos);
+ ncThis->fRecursionCount--;
+ }
+ }
+}
+
+void
+NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos) const
+{
+ NFRule *rule = findDoubleRule(number);
+ if (rule) { // else error, but can't report it
+ NFRuleSet* ncThis = (NFRuleSet*)this;
+ if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) {
+ // stop recursion
+ ncThis->fRecursionCount = 0;
+ } else {
+ rule->doFormat(number, toAppendTo, pos);
+ ncThis->fRecursionCount--;
+ }
+ }
+}
+
+NFRule*
+NFRuleSet::findDoubleRule(double number) const
+{
+ // if this is a fraction rule set, use findFractionRuleSetRule()
+ if (isFractionRuleSet()) {
+ return findFractionRuleSetRule(number);
+ }
+
+ // if the number is negative, return the negative number rule
+ // (if there isn't a negative-number rule, we pretend it's a
+ // positive number)
+ if (number < 0) {
+ if (negativeNumberRule) {
+ return negativeNumberRule;
+ } else {
+ number = -number;
+ }
+ }
+
+ // if the number isn't an integer, we use one of the fraction rules...
+ if (number != uprv_floor(number)) {
+ // if the number is between 0 and 1, return the proper
+ // fraction rule
+ if (number < 1 && fractionRules[1]) {
+ return fractionRules[1];
+ }
+ // otherwise, return the improper fraction rule
+ else if (fractionRules[0]) {
+ return fractionRules[0];
+ }
+ }
+
+ // if there's a master rule, use it to format the number
+ if (fractionRules[2]) {
+ return fractionRules[2];
+ }
+
+ // and if we haven't yet returned a rule, use findNormalRule()
+ // to find the applicable rule
+ int64_t r = util64_fromDouble(number + 0.5);
+ return findNormalRule(r);
+}
+
+NFRule *
+NFRuleSet::findNormalRule(int64_t number) const
+{
+ // if this is a fraction rule set, use findFractionRuleSetRule()
+ // to find the rule (we should only go into this clause if the
+ // value is 0)
+ if (fIsFractionRuleSet) {
+ return findFractionRuleSetRule((double)number);
+ }
+
+ // if the number is negative, return the negative-number rule
+ // (if there isn't one, pretend the number is positive)
+ if (number < 0) {
+ if (negativeNumberRule) {
+ return negativeNumberRule;
+ } else {
+ number = -number;
+ }
+ }
+
+ // we have to repeat the preceding two checks, even though we
+ // do them in findRule(), because the version of format() that
+ // takes a long bypasses findRule() and goes straight to this
+ // function. This function does skip the fraction rules since
+ // we know the value is an integer (it also skips the master
+ // rule, since it's considered a fraction rule. Skipping the
+ // master rule in this function is also how we avoid infinite
+ // recursion)
+
+ // {dlf} unfortunately this fails if there are no rules except
+ // special rules. If there are no rules, use the master rule.
+
+ // binary-search the rule list for the applicable rule
+ // (a rule is used for all values from its base value to
+ // the next rule's base value)
+ int32_t hi = rules.size();
+ if (hi > 0) {
+ int32_t lo = 0;
+
+ while (lo < hi) {
+ int32_t mid = (lo + hi) / 2;
+ if (rules[mid]->getBaseValue() == number) {
+ return rules[mid];
+ }
+ else if (rules[mid]->getBaseValue() > number) {
+ hi = mid;
+ }
+ else {
+ lo = mid + 1;
+ }
+ }
+ if (hi == 0) { // bad rule set, minimum base > 0
+ return NULL; // want to throw exception here
+ }
+
+ NFRule *result = rules[hi - 1];
+
+ // use shouldRollBack() to see whether we need to invoke the
+ // rollback rule (see shouldRollBack()'s documentation for
+ // an explanation of the rollback rule). If we do, roll back
+ // one rule and return that one instead of the one we'd normally
+ // return
+ if (result->shouldRollBack((double)number)) {
+ if (hi == 1) { // bad rule set, no prior rule to rollback to from this base
+ return NULL;
+ }
+ result = rules[hi - 2];
+ }
+ return result;
+ }
+ // else use the master rule
+ return fractionRules[2];
+}
+
+/**
+ * If this rule is a fraction rule set, this function is used by
+ * findRule() to select the most appropriate rule for formatting
+ * the number. Basically, the base value of each rule in the rule
+ * set is treated as the denominator of a fraction. Whichever
+ * denominator can produce the fraction closest in value to the
+ * number passed in is the result. If there's a tie, the earlier
+ * one in the list wins. (If there are two rules in a row with the
+ * same base value, the first one is used when the numerator of the
+ * fraction would be 1, and the second rule is used the rest of the
+ * time.
+ * @param number The number being formatted (which will always be
+ * a number between 0 and 1)
+ * @return The rule to use to format this number
+ */
+NFRule*
+NFRuleSet::findFractionRuleSetRule(double number) const
+{
+ // the obvious way to do this (multiply the value being formatted
+ // by each rule's base value until you get an integral result)
+ // doesn't work because of rounding error. This method is more
+ // accurate
+
+ // find the least common multiple of the rules' base values
+ // and multiply this by the number being formatted. This is
+ // all the precision we need, and we can do all of the rest
+ // of the math using integer arithmetic
+ int64_t leastCommonMultiple = rules[0]->getBaseValue();
+ int64_t numerator;
+ {
+ for (uint32_t i = 1; i < rules.size(); ++i) {
+ leastCommonMultiple = util_lcm(leastCommonMultiple, rules[i]->getBaseValue());
+ }
+ numerator = util64_fromDouble(number * (double)leastCommonMultiple + 0.5);
+ }
+ // for each rule, do the following...
+ int64_t tempDifference;
+ int64_t difference = util64_fromDouble(uprv_maxMantissa());
+ int32_t winner = 0;
+ for (uint32_t i = 0; i < rules.size(); ++i) {
+ // "numerator" is the numerator of the fraction if the
+ // denominator is the LCD. The numerator if the rule's
+ // base value is the denominator is "numerator" times the
+ // base value divided bythe LCD. Here we check to see if
+ // that's an integer, and if not, how close it is to being
+ // an integer.
+ tempDifference = numerator * rules[i]->getBaseValue() % leastCommonMultiple;
+
+
+ // normalize the result of the above calculation: we want
+ // the numerator's distance from the CLOSEST multiple
+ // of the LCD
+ if (leastCommonMultiple - tempDifference < tempDifference) {
+ tempDifference = leastCommonMultiple - tempDifference;
+ }
+
+ // if this is as close as we've come, keep track of how close
+ // that is, and the line number of the rule that did it. If
+ // we've scored a direct hit, we don't have to look at any more
+ // rules
+ if (tempDifference < difference) {
+ difference = tempDifference;
+ winner = i;
+ if (difference == 0) {
+ break;
+ }
+ }
+ }
+
+ // if we have two successive rules that both have the winning base
+ // value, then the first one (the one we found above) is used if
+ // the numerator of the fraction is 1 and the second one is used if
+ // the numerator of the fraction is anything else (this lets us
+ // do things like "one third"/"two thirds" without haveing to define
+ // a whole bunch of extra rule sets)
+ if ((unsigned)(winner + 1) < rules.size() &&
+ rules[winner + 1]->getBaseValue() == rules[winner]->getBaseValue()) {
+ double n = ((double)rules[winner]->getBaseValue()) * number;
+ if (n < 0.5 || n >= 2) {
+ ++winner;
+ }
+ }
+
+ // finally, return the winning rule
+ return rules[winner];
+}
+
+/**
+ * Parses a string. Matches the string to be parsed against each
+ * of its rules (with a base value less than upperBound) and returns
+ * the value produced by the rule that matched the most charcters
+ * in the source string.
+ * @param text The string to parse
+ * @param parsePosition The initial position is ignored and assumed
+ * to be 0. On exit, this object has been updated to point to the
+ * first character position this rule set didn't consume.
+ * @param upperBound Limits the rules that can be allowed to match.
+ * Only rules whose base values are strictly less than upperBound
+ * are considered.
+ * @return The numerical result of parsing this string. This will
+ * be the matching rule's base value, composed appropriately with
+ * the results of matching any of its substitutions. The object
+ * will be an instance of Long if it's an integral value; otherwise,
+ * it will be an instance of Double. This function always returns
+ * a valid object: If nothing matched the input string at all,
+ * this function returns new Long(0), and the parse position is
+ * left unchanged.
+ */
+#ifdef RBNF_DEBUG
+#include <stdio.h>
+
+static void dumpUS(FILE* f, const UnicodeString& us) {
+ int len = us.length();
+ char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
+ 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.6/i18n/nfrs.h b/Build/source/libs/icu/icu-4.6/i18n/nfrs.h
new file mode 100644
index 00000000000..93a29b08ee7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nfrule.cpp b/Build/source/libs/icu/icu-4.6/i18n/nfrule.cpp
new file mode 100644
index 00000000000..d73a57062ee
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/nfrule.cpp
@@ -0,0 +1,1476 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2008, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfrule.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#include "nfrule.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/rbnf.h"
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/uchar.h"
+#include "nfrs.h"
+#include "nfrlist.h"
+#include "nfsubs.h"
+
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+NFRule::NFRule(const RuleBasedNumberFormat* _rbnf)
+ : baseValue((int32_t)0)
+ , radix(0)
+ , exponent(0)
+ , ruleText()
+ , sub1(NULL)
+ , sub2(NULL)
+ , formatter(_rbnf)
+{
+}
+
+NFRule::~NFRule()
+{
+ delete sub1;
+ delete sub2;
+}
+
+static const UChar gLeftBracket = 0x005b;
+static const UChar gRightBracket = 0x005d;
+static const UChar gColon = 0x003a;
+static const UChar gZero = 0x0030;
+static const UChar gNine = 0x0039;
+static const UChar gSpace = 0x0020;
+static const UChar gSlash = 0x002f;
+static const UChar gGreaterThan = 0x003e;
+static const UChar gLessThan = 0x003c;
+static const UChar gComma = 0x002c;
+static const UChar gDot = 0x002e;
+static const UChar gTick = 0x0027;
+//static const UChar gMinus = 0x002d;
+static const UChar gSemicolon = 0x003b;
+
+static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */
+static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x" */
+static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0" */
+static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x" */
+
+static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */
+static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */
+static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */
+static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */
+static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */
+static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */
+static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */
+static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */
+static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */
+static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */
+static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */
+static const UChar gEmptyString[] = {0}; /* "" */
+static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */
+
+static const UChar * const tokenStrings[] = {
+ gLessLess, gLessPercent, gLessHash, gLessZero,
+ gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero,
+ gEqualPercent, gEqualHash, gEqualZero, NULL
+};
+
+void
+NFRule::makeRules(UnicodeString& description,
+ const NFRuleSet *ruleSet,
+ const NFRule *predecessor,
+ const RuleBasedNumberFormat *rbnf,
+ NFRuleList& rules,
+ UErrorCode& status)
+{
+ // we know we're making at least one rule, so go ahead and
+ // new it up and initialize its basevalue and divisor
+ // (this also strips the rule descriptor, if any, off the
+ // descripton string)
+ NFRule* rule1 = new NFRule(rbnf);
+ /* test for NULL */
+ if (rule1 == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ rule1->parseRuleDescriptor(description, status);
+
+ // check the description to see whether there's text enclosed
+ // in brackets
+ int32_t brack1 = description.indexOf(gLeftBracket);
+ int32_t brack2 = description.indexOf(gRightBracket);
+
+ // if the description doesn't contain a matched pair of brackets,
+ // or if it's of a type that doesn't recognize bracketed text,
+ // then leave the description alone, initialize the rule's
+ // rule text and substitutions, and return that rule
+ if (brack1 == -1 || brack2 == -1 || brack1 > brack2
+ || rule1->getType() == kProperFractionRule
+ || rule1->getType() == kNegativeNumberRule) {
+ rule1->ruleText = description;
+ rule1->extractSubstitutions(ruleSet, predecessor, rbnf, status);
+ rules.add(rule1);
+ } else {
+ // if the description does contain a matched pair of brackets,
+ // then it's really shorthand for two rules (with one exception)
+ NFRule* rule2 = NULL;
+ UnicodeString sbuf;
+
+ // we'll actually only split the rule into two rules if its
+ // base value is an even multiple of its divisor (or it's one
+ // of the special rules)
+ if ((rule1->baseValue > 0
+ && (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0)
+ || rule1->getType() == kImproperFractionRule
+ || rule1->getType() == kMasterRule) {
+
+ // if it passes that test, new up the second rule. If the
+ // rule set both rules will belong to is a fraction rule
+ // set, they both have the same base value; otherwise,
+ // increment the original rule's base value ("rule1" actually
+ // goes SECOND in the rule set's rule list)
+ rule2 = new NFRule(rbnf);
+ /* test for NULL */
+ if (rule2 == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (rule1->baseValue >= 0) {
+ rule2->baseValue = rule1->baseValue;
+ if (!ruleSet->isFractionRuleSet()) {
+ ++rule1->baseValue;
+ }
+ }
+
+ // if the description began with "x.x" and contains bracketed
+ // text, it describes both the improper fraction rule and
+ // the proper fraction rule
+ else if (rule1->getType() == kImproperFractionRule) {
+ rule2->setType(kProperFractionRule);
+ }
+
+ // if the description began with "x.0" and contains bracketed
+ // text, it describes both the master rule and the
+ // improper fraction rule
+ else if (rule1->getType() == kMasterRule) {
+ rule2->baseValue = rule1->baseValue;
+ rule1->setType(kImproperFractionRule);
+ }
+
+ // both rules have the same radix and exponent (i.e., the
+ // same divisor)
+ rule2->radix = rule1->radix;
+ rule2->exponent = rule1->exponent;
+
+ // rule2's rule text omits the stuff in brackets: initalize
+ // its rule text and substitutions accordingly
+ sbuf.append(description, 0, brack1);
+ if (brack2 + 1 < description.length()) {
+ sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
+ }
+ rule2->ruleText.setTo(sbuf);
+ rule2->extractSubstitutions(ruleSet, predecessor, rbnf, status);
+ }
+
+ // rule1's text includes the text in the brackets but omits
+ // the brackets themselves: initialize _its_ rule text and
+ // substitutions accordingly
+ sbuf.setTo(description, 0, brack1);
+ sbuf.append(description, brack1 + 1, brack2 - brack1 - 1);
+ if (brack2 + 1 < description.length()) {
+ sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
+ }
+ rule1->ruleText.setTo(sbuf);
+ rule1->extractSubstitutions(ruleSet, predecessor, rbnf, status);
+
+ // if we only have one rule, return it; if we have two, return
+ // a two-element array containing them (notice that rule2 goes
+ // BEFORE rule1 in the list: in all cases, rule2 OMITS the
+ // material in the brackets and rule1 INCLUDES the material
+ // in the brackets)
+ if (rule2 != NULL) {
+ rules.add(rule2);
+ }
+ rules.add(rule1);
+ }
+}
+
+/**
+ * This function parses the rule's rule descriptor (i.e., the base
+ * value and/or other tokens that precede the rule's rule text
+ * in the description) and sets the rule's base value, radix, and
+ * exponent according to the descriptor. (If the description doesn't
+ * include a rule descriptor, then this function sets everything to
+ * default values and the rule set sets the rule's real base value).
+ * @param description The rule's description
+ * @return If "description" included a rule descriptor, this is
+ * "description" with the descriptor and any trailing whitespace
+ * stripped off. Otherwise; it's "descriptor" unchangd.
+ */
+void
+NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
+{
+ // the description consists of a rule descriptor and a rule body,
+ // separated by a colon. The rule descriptor is optional. If
+ // it's omitted, just set the base value to 0.
+ int32_t p = description.indexOf(gColon);
+ if (p == -1) {
+ setBaseValue((int32_t)0, status);
+ } else {
+ // copy the descriptor out into its own string and strip it,
+ // along with any trailing whitespace, out of the original
+ // description
+ UnicodeString descriptor;
+ descriptor.setTo(description, 0, p);
+
+ ++p;
+ while (p < description.length() && uprv_isRuleWhiteSpace(description.charAt(p))) {
+ ++p;
+ }
+ description.removeBetween(0, p);
+
+ // check first to see if the rule descriptor matches the token
+ // for one of the special rules. If it does, set the base
+ // value to the correct identfier value
+ if (descriptor == gMinusX) {
+ setType(kNegativeNumberRule);
+ }
+ else if (descriptor == gXDotX) {
+ setType(kImproperFractionRule);
+ }
+ else if (descriptor == gZeroDotX) {
+ setType(kProperFractionRule);
+ }
+ else if (descriptor == gXDotZero) {
+ setType(kMasterRule);
+ }
+
+ // if the rule descriptor begins with a digit, it's a descriptor
+ // for a normal rule
+ // since we don't have Long.parseLong, and this isn't much work anyway,
+ // just build up the value as we encounter the digits.
+ else if (descriptor.charAt(0) >= gZero && descriptor.charAt(0) <= gNine) {
+ int64_t val = 0;
+ p = 0;
+ UChar c = gSpace;
+
+ // begin parsing the descriptor: copy digits
+ // into "tempValue", skip periods, commas, and spaces,
+ // stop on a slash or > sign (or at the end of the string),
+ // and throw an exception on any other character
+ int64_t ll_10 = 10;
+ while (p < descriptor.length()) {
+ c = descriptor.charAt(p);
+ if (c >= gZero && c <= gNine) {
+ val = val * ll_10 + (int32_t)(c - gZero);
+ }
+ else if (c == gSlash || c == gGreaterThan) {
+ break;
+ }
+ else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+ }
+ else {
+ // throw new IllegalArgumentException("Illegal character in rule descriptor");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ ++p;
+ }
+
+ // we have the base value, so set it
+ setBaseValue(val, status);
+
+ // if we stopped the previous loop on a slash, we're
+ // now parsing the rule's radix. Again, accumulate digits
+ // in tempValue, skip punctuation, stop on a > mark, and
+ // throw an exception on anything else
+ if (c == gSlash) {
+ val = 0;
+ ++p;
+ int64_t ll_10 = 10;
+ while (p < descriptor.length()) {
+ c = descriptor.charAt(p);
+ if (c >= gZero && c <= gNine) {
+ val = val * ll_10 + (int32_t)(c - gZero);
+ }
+ else if (c == gGreaterThan) {
+ break;
+ }
+ else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+ }
+ else {
+ // throw new IllegalArgumentException("Illegal character is rule descriptor");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ ++p;
+ }
+
+ // tempValue now contain's the rule's radix. Set it
+ // accordingly, and recalculate the rule's exponent
+ radix = (int32_t)val;
+ if (radix == 0) {
+ // throw new IllegalArgumentException("Rule can't have radix of 0");
+ status = U_PARSE_ERROR;
+ }
+
+ exponent = expectedExponent();
+ }
+
+ // if we stopped the previous loop on a > sign, then continue
+ // for as long as we still see > signs. For each one,
+ // decrement the exponent (unless the exponent is already 0).
+ // If we see another character before reaching the end of
+ // the descriptor, that's also a syntax error.
+ if (c == gGreaterThan) {
+ while (p < descriptor.length()) {
+ c = descriptor.charAt(p);
+ if (c == gGreaterThan && exponent > 0) {
+ --exponent;
+ } else {
+ // throw new IllegalArgumentException("Illegal character in rule descriptor");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ ++p;
+ }
+ }
+ }
+ }
+
+ // finally, if the rule body begins with an apostrophe, strip it off
+ // (this is generally used to put whitespace at the beginning of
+ // a rule's rule text)
+ if (description.length() > 0 && description.charAt(0) == gTick) {
+ description.removeBetween(0, 1);
+ }
+
+ // return the description with all the stuff we've just waded through
+ // stripped off the front. It now contains just the rule body.
+ // return description;
+}
+
+/**
+* Searches the rule's rule text for the substitution tokens,
+* creates the substitutions, and removes the substitution tokens
+* from the rule's rule text.
+* @param owner The rule set containing this rule
+* @param predecessor The rule preseding this one in "owners" rule list
+* @param ownersOwner The RuleBasedFormat that owns this rule
+*/
+void
+NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
+ const NFRule* predecessor,
+ const RuleBasedNumberFormat* rbnf,
+ UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ sub1 = extractSubstitution(ruleSet, predecessor, rbnf, status);
+ sub2 = extractSubstitution(ruleSet, predecessor, rbnf, status);
+ }
+}
+
+/**
+* Searches the rule's rule text for the first substitution token,
+* creates a substitution based on it, and removes the token from
+* the rule's rule text.
+* @param owner The rule set containing this rule
+* @param predecessor The rule preceding this one in the rule set's
+* rule list
+* @param ownersOwner The RuleBasedNumberFormat that owns this rule
+* @return The newly-created substitution. This is never null; if
+* the rule text doesn't contain any substitution tokens, this will
+* be a NullSubstitution.
+*/
+NFSubstitution *
+NFRule::extractSubstitution(const NFRuleSet* ruleSet,
+ const NFRule* predecessor,
+ const RuleBasedNumberFormat* rbnf,
+ UErrorCode& status)
+{
+ NFSubstitution* result = NULL;
+
+ // search the rule's rule text for the first two characters of
+ // a substitution token
+ int32_t subStart = indexOfAny(tokenStrings);
+ int32_t subEnd = subStart;
+
+ // if we didn't find one, create a null substitution positioned
+ // at the end of the rule text
+ if (subStart == -1) {
+ return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
+ ruleSet, rbnf, gEmptyString, status);
+ }
+
+ // special-case the ">>>" token, since searching for the > at the
+ // end will actually find the > in the middle
+ if (ruleText.indexOf(gGreaterGreaterGreater) == subStart) {
+ subEnd = subStart + 2;
+
+ // otherwise the substitution token ends with the same character
+ // it began with
+ } else {
+ UChar c = ruleText.charAt(subStart);
+ subEnd = ruleText.indexOf(c, subStart + 1);
+ // special case for '<%foo<<'
+ if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) {
+ // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '==' in the middle
+ // occurs because of the juxtaposition of two different rules. The check for '<' is a hack
+ // to get around this. Having the duplicate at the front would cause problems with
+ // rules like "<<%" to format, say, percents...
+ ++subEnd;
+ }
+ }
+
+ // if we don't find the end of the token (i.e., if we're on a single,
+ // unmatched token character), create a null substitution positioned
+ // at the end of the rule
+ if (subEnd == -1) {
+ return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
+ ruleSet, rbnf, gEmptyString, status);
+ }
+
+ // if we get here, we have a real substitution token (or at least
+ // some text bounded by substitution token characters). Use
+ // makeSubstitution() to create the right kind of substitution
+ UnicodeString subToken;
+ subToken.setTo(ruleText, subStart, subEnd + 1 - subStart);
+ result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleSet,
+ rbnf, subToken, status);
+
+ // remove the substitution from the rule text
+ ruleText.removeBetween(subStart, subEnd+1);
+
+ return result;
+}
+
+/**
+ * Sets the rule's base value, and causes the radix and exponent
+ * to be recalculated. This is used during construction when we
+ * don't know the rule's base value until after it's been
+ * constructed. It should be used at any other time.
+ * @param The new base value for the rule.
+ */
+void
+NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status)
+{
+ // set the base value
+ baseValue = newBaseValue;
+
+ // if this isn't a special rule, recalculate the radix and exponent
+ // (the radix always defaults to 10; if it's supposed to be something
+ // else, it's cleaned up by the caller and the exponent is
+ // recalculated again-- the only function that does this is
+ // NFRule.parseRuleDescriptor() )
+ if (baseValue >= 1) {
+ radix = 10;
+ exponent = expectedExponent();
+
+ // this function gets called on a fully-constructed rule whose
+ // description didn't specify a base value. This means it
+ // has substitutions, and some substitutions hold on to copies
+ // of the rule's divisor. Fix their copies of the divisor.
+ if (sub1 != NULL) {
+ sub1->setDivisor(radix, exponent, status);
+ }
+ if (sub2 != NULL) {
+ sub2->setDivisor(radix, exponent, status);
+ }
+
+ // if this is a special rule, its radix and exponent are basically
+ // ignored. Set them to "safe" default values
+ } else {
+ radix = 10;
+ exponent = 0;
+ }
+}
+
+/**
+* This calculates the rule's exponent based on its radix and base
+* value. This will be the highest power the radix can be raised to
+* and still produce a result less than or equal to the base value.
+*/
+int16_t
+NFRule::expectedExponent() const
+{
+ // since the log of 0, or the log base 0 of something, causes an
+ // error, declare the exponent in these cases to be 0 (we also
+ // deal with the special-rule identifiers here)
+ if (radix == 0 || baseValue < 1) {
+ return 0;
+ }
+
+ // we get rounding error in some cases-- for example, log 1000 / log 10
+ // gives us 1.9999999996 instead of 2. The extra logic here is to take
+ // that into account
+ int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((double)radix));
+ int64_t temp = util64_pow(radix, tempResult + 1);
+ if (temp <= baseValue) {
+ tempResult += 1;
+ }
+ return tempResult;
+}
+
+/**
+ * Searches the rule's rule text for any of the specified strings.
+ * @param strings An array of strings to search the rule's rule
+ * text for
+ * @return The index of the first match in the rule's rule text
+ * (i.e., the first substring in the rule's rule text that matches
+ * _any_ of the strings in "strings"). If none of the strings in
+ * "strings" is found in the rule's rule text, returns -1.
+ */
+int32_t
+NFRule::indexOfAny(const UChar* const strings[]) const
+{
+ int result = -1;
+ for (int i = 0; strings[i]; i++) {
+ int32_t pos = ruleText.indexOf(*strings[i]);
+ if (pos != -1 && (result == -1 || pos < result)) {
+ result = pos;
+ }
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------
+// boilerplate
+//-----------------------------------------------------------------------
+
+/**
+* Tests two rules for equality.
+* @param that The rule to compare this one against
+* @return True is the two rules are functionally equivalent
+*/
+UBool
+NFRule::operator==(const NFRule& rhs) const
+{
+ return baseValue == rhs.baseValue
+ && radix == rhs.radix
+ && exponent == rhs.exponent
+ && ruleText == rhs.ruleText
+ && *sub1 == *rhs.sub1
+ && *sub2 == *rhs.sub2;
+}
+
+/**
+* Returns a textual representation of the rule. This won't
+* necessarily be the same as the description that this rule
+* was created with, but it will produce the same result.
+* @return A textual description of the rule
+*/
+static void util_append64(UnicodeString& result, int64_t n)
+{
+ UChar buffer[256];
+ int32_t len = util64_tou(n, buffer, sizeof(buffer));
+ UnicodeString temp(buffer, len);
+ result.append(temp);
+}
+
+void
+NFRule::_appendRuleText(UnicodeString& result) const
+{
+ switch (getType()) {
+ case kNegativeNumberRule: result.append(gMinusX); break;
+ case kImproperFractionRule: result.append(gXDotX); break;
+ case kProperFractionRule: result.append(gZeroDotX); break;
+ case kMasterRule: result.append(gXDotZero); break;
+ default:
+ // for a normal rule, write out its base value, and if the radix is
+ // something other than 10, write out the radix (with the preceding
+ // slash, of course). Then calculate the expected exponent and if
+ // if isn't the same as the actual exponent, write an appropriate
+ // number of > signs. Finally, terminate the whole thing with
+ // a colon.
+ util_append64(result, baseValue);
+ if (radix != 10) {
+ result.append(gSlash);
+ util_append64(result, radix);
+ }
+ int numCarets = expectedExponent() - exponent;
+ for (int i = 0; i < numCarets; i++) {
+ result.append(gGreaterThan);
+ }
+ break;
+ }
+ result.append(gColon);
+ result.append(gSpace);
+
+ // if the rule text begins with a space, write an apostrophe
+ // (whitespace after the rule descriptor is ignored; the
+ // apostrophe is used to make the whitespace significant)
+ if (ruleText.startsWith(gSpace) && sub1->getPos() != 0) {
+ result.append(gTick);
+ }
+
+ // now, write the rule's rule text, inserting appropriate
+ // substitution tokens in the appropriate places
+ UnicodeString ruleTextCopy;
+ ruleTextCopy.setTo(ruleText);
+
+ UnicodeString temp;
+ sub2->toString(temp);
+ ruleTextCopy.insert(sub2->getPos(), temp);
+ sub1->toString(temp);
+ ruleTextCopy.insert(sub1->getPos(), temp);
+
+ result.append(ruleTextCopy);
+
+ // and finally, top the whole thing off with a semicolon and
+ // return the result
+ result.append(gSemicolon);
+}
+
+//-----------------------------------------------------------------------
+// formatting
+//-----------------------------------------------------------------------
+
+/**
+* Formats the number, and inserts the resulting text into
+* toInsertInto.
+* @param number The number being formatted
+* @param toInsertInto The string where the resultant text should
+* be inserted
+* @param pos The position in toInsertInto where the resultant text
+* should be inserted
+*/
+void
+NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos) const
+{
+ // first, insert the rule's rule text into toInsertInto at the
+ // specified position, then insert the results of the substitutions
+ // into the right places in toInsertInto (notice we do the
+ // substitutions in reverse order so that the offsets don't get
+ // messed up)
+ toInsertInto.insert(pos, ruleText);
+ sub2->doSubstitution(number, toInsertInto, pos);
+ sub1->doSubstitution(number, toInsertInto, pos);
+}
+
+/**
+* Formats the number, and inserts the resulting text into
+* toInsertInto.
+* @param number The number being formatted
+* @param toInsertInto The string where the resultant text should
+* be inserted
+* @param pos The position in toInsertInto where the resultant text
+* should be inserted
+*/
+void
+NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos) const
+{
+ // first, insert the rule's rule text into toInsertInto at the
+ // specified position, then insert the results of the substitutions
+ // into the right places in toInsertInto
+ // [again, we have two copies of this routine that do the same thing
+ // so that we don't sacrifice precision in a long by casting it
+ // to a double]
+ toInsertInto.insert(pos, ruleText);
+ sub2->doSubstitution(number, toInsertInto, pos);
+ sub1->doSubstitution(number, toInsertInto, pos);
+}
+
+/**
+* Used by the owning rule set to determine whether to invoke the
+* rollback rule (i.e., whether this rule or the one that precedes
+* it in the rule set's list should be used to format the number)
+* @param The number being formatted
+* @return True if the rule set should use the rule that precedes
+* this one in its list; false if it should use this rule
+*/
+UBool
+NFRule::shouldRollBack(double number) const
+{
+ // we roll back if the rule contains a modulus substitution,
+ // the number being formatted is an even multiple of the rule's
+ // divisor, and the rule's base value is NOT an even multiple
+ // of its divisor
+ // In other words, if the original description had
+ // 100: << hundred[ >>];
+ // that expands into
+ // 100: << hundred;
+ // 101: << hundred >>;
+ // internally. But when we're formatting 200, if we use the rule
+ // at 101, which would normally apply, we get "two hundred zero".
+ // To prevent this, we roll back and use the rule at 100 instead.
+ // This is the logic that makes this happen: the rule at 101 has
+ // a modulus substitution, its base value isn't an even multiple
+ // of 100, and the value we're trying to format _is_ an even
+ // multiple of 100. This is called the "rollback rule."
+ if ((sub1->isModulusSubstitution()) || (sub2->isModulusSubstitution())) {
+ int64_t re = util64_pow(radix, exponent);
+ return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------
+// parsing
+//-----------------------------------------------------------------------
+
+/**
+* Attempts to parse the string with this rule.
+* @param text The string being parsed
+* @param parsePosition On entry, the value is ignored and assumed to
+* be 0. On exit, this has been updated with the position of the first
+* character not consumed by matching the text against this rule
+* (if this rule doesn't match the text at all, the parse position
+* if left unchanged (presumably at 0) and the function returns
+* new Long(0)).
+* @param isFractionRule True if this rule is contained within a
+* fraction rule set. This is only used if the rule has no
+* substitutions.
+* @return If this rule matched the text, this is the rule's base value
+* combined appropriately with the results of parsing the substitutions.
+* If nothing matched, this is new Long(0) and the parse position is
+* left unchanged. The result will be an instance of Long if the
+* result is an integer and Double otherwise. The result is never null.
+*/
+#ifdef RBNF_DEBUG
+#include <stdio.h>
+
+static void dumpUS(FILE* f, const UnicodeString& us) {
+ int len = us.length();
+ char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
+ 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.6/i18n/nfrule.h b/Build/source/libs/icu/icu-4.6/i18n/nfrule.h
new file mode 100644
index 00000000000..8422a20c1d6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nfsubs.cpp b/Build/source/libs/icu/icu-4.6/i18n/nfsubs.cpp
new file mode 100644
index 00000000000..4348f5d4fc1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nfsubs.h b/Build/source/libs/icu/icu-4.6/i18n/nfsubs.h
new file mode 100644
index 00000000000..644b4b2f6e1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nortrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/nortrans.cpp
new file mode 100644
index 00000000000..329fb910521
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nortrans.h b/Build/source/libs/icu/icu-4.6/i18n/nortrans.h
new file mode 100644
index 00000000000..634f534f7d4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nultrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/nultrans.cpp
new file mode 100644
index 00000000000..820c43d07e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/nultrans.h b/Build/source/libs/icu/icu-4.6/i18n/nultrans.h
new file mode 100644
index 00000000000..699c323f8c6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/numfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/numfmt.cpp
new file mode 100644
index 00000000000..dcd24a7406b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/numfmt.cpp
@@ -0,0 +1,1299 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 "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 "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[] =
+{
+ gLastResortDecimalPat,
+ gLastResortCurrencyPat,
+ gLastResortPercentPat,
+ gLastResortScientificPat,
+ gLastResortIsoCurrencyPat,
+ gLastResortPluralCurrencyPat,
+};
+
+// 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[] = { "decimalFormat", "currencyFormat", "percentFormat", "scientificFormat" };
+
+// 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)
+{
+ 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);
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+NumberFormat::operator==(const Format& that) const
+{
+ // Format::operator== guarantees this cast is safe
+ NumberFormat* other = (NumberFormat*)&that;
+
+#ifdef FMT_DEBUG
+ // This code makes it easy to determine why two format objects that should
+ // be equal aren't.
+ UBool first = TRUE;
+ if (!Format::operator==(that)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Format::!=");
+ }
+ if (!(fMaxIntegerDigits == other->fMaxIntegerDigits &&
+ fMinIntegerDigits == other->fMinIntegerDigits)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Integer digits !=");
+ }
+ if (!(fMaxFractionDigits == other->fMaxFractionDigits &&
+ fMinFractionDigits == other->fMinFractionDigits)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Fraction digits !=");
+ }
+ if (!(fGroupingUsed == other->fGroupingUsed)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fGroupingUsed != ");
+ }
+ if (!(fParseIntegerOnly == other->fParseIntegerOnly)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fParseIntegerOnly != ");
+ }
+ if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fCurrency !=");
+ }
+ if (!first) { printf(" ]"); }
+#endif
+
+ return ((this == &that) ||
+ ((Format::operator==(that) &&
+ fMaxIntegerDigits == other->fMaxIntegerDigits &&
+ fMinIntegerDigits == other->fMinIntegerDigits &&
+ fMaxFractionDigits == other->fMaxFractionDigits &&
+ fMinFractionDigits == other->fMinFractionDigits &&
+ fGroupingUsed == other->fGroupingUsed &&
+ fParseIntegerOnly == other->fParseIntegerOnly &&
+ u_strcmp(fCurrency, other->fCurrency) == 0)));
+}
+
+// -------------------------------------
+// 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;
+}
+
+// -------------------------------------
+// Create a number style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), kNumberStyle, status);
+}
+
+// -------------------------------------
+// Create a number style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kNumberStyle, status);
+}
+
+// -------------------------------------
+// Create a currency style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createCurrencyInstance(UErrorCode& status)
+{
+ return createCurrencyInstance(Locale::getDefault(), status);
+}
+
+// -------------------------------------
+// Create a currency style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kCurrencyStyle, status);
+}
+
+// -------------------------------------
+// Create a percent style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createPercentInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), kPercentStyle, status);
+}
+
+// -------------------------------------
+// Create a percent style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kPercentStyle, status);
+}
+
+// -------------------------------------
+// Create a scientific style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createScientificInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), kScientificStyle, status);
+}
+
+// -------------------------------------
+// Create a scientific style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kScientificStyle, status);
+}
+
+// -------------------------------------
+
+const Locale* U_EXPORT2
+NumberFormat::getAvailableLocales(int32_t& count)
+{
+ return Locale::getAvailableLocales(count);
+}
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+
+#if !UCONFIG_NO_SERVICE
+
+// -------------------------------------
+
+class ICUNumberFormatFactory : public ICUResourceBundleFactory {
+protected:
+ virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
+ // !!! kind is not an EStyles, need to determine how to handle this
+ return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
+ }
+};
+
+// -------------------------------------
+
+class NFFactory : public LocaleKeyFactory {
+private:
+ NumberFormatFactory* _delegate;
+ Hashtable* _ids;
+
+public:
+ NFFactory(NumberFormatFactory* delegate)
+ : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
+ , _delegate(delegate)
+ , _ids(NULL)
+ {
+ }
+
+ virtual ~NFFactory()
+ {
+ delete _delegate;
+ delete _ids;
+ }
+
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
+ {
+ if (handlesKey(key, status)) {
+ const LocaleKey& lkey = (const LocaleKey&)key;
+ Locale loc;
+ lkey.canonicalLocale(loc);
+ int32_t kind = lkey.kind();
+
+ UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1));
+ if (result == NULL) {
+ result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
+ }
+ return result;
+ }
+ return NULL;
+ }
+
+protected:
+ /**
+ * Return the set of ids that this factory supports (visible or
+ * otherwise). This can be called often and might need to be
+ * cached if it is expensive to create.
+ */
+ virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
+ {
+ if (U_SUCCESS(status)) {
+ if (!_ids) {
+ int32_t count = 0;
+ const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status);
+ ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */
+ if (_ids) {
+ for (int i = 0; i < count; ++i) {
+ _ids->put(idlist[i], (void*)this, status);
+ }
+ }
+ }
+ return _ids;
+ }
+ return NULL;
+ }
+};
+
+class ICUNumberFormatService : public ICULocaleService {
+public:
+ ICUNumberFormatService()
+ : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format"))
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ registerFactory(new ICUNumberFormatFactory(), status);
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return ((NumberFormat*)instance)->clone();
+ }
+
+ virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const {
+ LocaleKey& lkey = (LocaleKey&)key;
+ int32_t kind = lkey.kind();
+ Locale loc;
+ lkey.currentLocale(loc);
+ return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
+ }
+
+ virtual UBool isDefault() const {
+ return countFactories() == 1;
+ }
+};
+
+// -------------------------------------
+
+static ICULocaleService*
+getNumberFormatService(void)
+{
+ UBool needInit;
+ UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
+ if (needInit) {
+ ICULocaleService * newservice = new ICUNumberFormatService();
+ if (newservice) {
+ umtx_lock(NULL);
+ if (gService == NULL) {
+ gService = newservice;
+ newservice = NULL;
+ }
+ umtx_unlock(NULL);
+ }
+ if (newservice) {
+ delete newservice;
+ } else {
+ // we won the contention, this thread can register cleanup.
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
+ }
+ }
+ return gService;
+}
+
+// -------------------------------------
+
+URegistryKey U_EXPORT2
+NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
+{
+ ICULocaleService *service = getNumberFormatService();
+ if (service) {
+ 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, EStyles kind, UErrorCode& status)
+{
+#if !UCONFIG_NO_SERVICE
+ UBool haveService;
+ UMTX_CHECK(NULL, gService != NULL, haveService);
+ if (haveService) {
+ return (NumberFormat*)gService->get(loc, kind, status);
+ }
+ else
+#endif
+ {
+ return makeInstance(loc, kind, status);
+ }
+}
+
+
+// -------------------------------------
+// Checks if the thousand/10 thousand grouping is used in the
+// NumberFormat instance.
+
+UBool
+NumberFormat::isGroupingUsed() const
+{
+ return fGroupingUsed;
+}
+
+// -------------------------------------
+// Sets to use the thousand/10 thousand grouping in the
+// NumberFormat instance.
+
+void
+NumberFormat::setGroupingUsed(UBool newValue)
+{
+ fGroupingUsed = newValue;
+}
+
+// -------------------------------------
+// Gets the maximum number of digits for the integral part for
+// this NumberFormat instance.
+
+int32_t NumberFormat::getMaximumIntegerDigits() const
+{
+ return fMaxIntegerDigits;
+}
+
+// -------------------------------------
+// Sets the maximum number of digits for the integral part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMaximumIntegerDigits(int32_t newValue)
+{
+ fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
+ if(fMinIntegerDigits > fMaxIntegerDigits)
+ fMinIntegerDigits = fMaxIntegerDigits;
+}
+
+// -------------------------------------
+// Gets the minimum number of digits for the integral part for
+// this NumberFormat instance.
+
+int32_t
+NumberFormat::getMinimumIntegerDigits() const
+{
+ return fMinIntegerDigits;
+}
+
+// -------------------------------------
+// Sets the minimum number of digits for the integral part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMinimumIntegerDigits(int32_t newValue)
+{
+ fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
+ if(fMinIntegerDigits > fMaxIntegerDigits)
+ fMaxIntegerDigits = fMinIntegerDigits;
+}
+
+// -------------------------------------
+// Gets the maximum number of digits for the fractional part for
+// this NumberFormat instance.
+
+int32_t
+NumberFormat::getMaximumFractionDigits() const
+{
+ return fMaxFractionDigits;
+}
+
+// -------------------------------------
+// Sets the maximum number of digits for the fractional part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMaximumFractionDigits(int32_t newValue)
+{
+ fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
+ if(fMaxFractionDigits < fMinFractionDigits)
+ fMinFractionDigits = fMaxFractionDigits;
+}
+
+// -------------------------------------
+// Gets the minimum number of digits for the fractional part for
+// this NumberFormat instance.
+
+int32_t
+NumberFormat::getMinimumFractionDigits() const
+{
+ return fMinFractionDigits;
+}
+
+// -------------------------------------
+// Sets the minimum number of digits for the fractional part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMinimumFractionDigits(int32_t newValue)
+{
+ fMinFractionDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
+ if (fMaxFractionDigits < fMinFractionDigits)
+ fMaxFractionDigits = fMinFractionDigits;
+}
+
+// -------------------------------------
+
+void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ if (theCurrency) {
+ u_strncpy(fCurrency, theCurrency, 3);
+ fCurrency[3] = 0;
+ } else {
+ fCurrency[0] = 0;
+ }
+}
+
+const UChar* NumberFormat::getCurrency() const {
+ return fCurrency;
+}
+
+void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
+ const UChar* c = getCurrency();
+ if (*c != 0) {
+ u_strncpy(result, c, 3);
+ result[3] = 0;
+ } else {
+ const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
+ if (loc == NULL) {
+ loc = uloc_getDefault();
+ }
+ ucurr_forLocale(loc, result, 4, &ec);
+ }
+}
+
+// -------------------------------------
+// Creates the NumberFormat instance of the specified style (number, currency,
+// or percent) for the desired locale.
+
+NumberFormat*
+NumberFormat::makeInstance(const Locale& desiredLocale,
+ EStyles style,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status)) return NULL;
+
+ if (style < 0 || style >= kStyleCount) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+#ifdef U_WINDOWS
+ char buffer[8];
+ int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
+
+ // if the locale has "@compat=host", create a host-specific NumberFormat
+ if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
+ Win32NumberFormat *f = NULL;
+ UBool curr = TRUE;
+
+ switch (style) {
+ case kNumberStyle:
+ curr = FALSE;
+ // fall-through
+
+ case kCurrencyStyle:
+ case kIsoCurrencyStyle: // do not support plural formatting here
+ case kPluralCurrencyStyle:
+ f = new Win32NumberFormat(desiredLocale, curr, status);
+
+ if (U_SUCCESS(status)) {
+ return f;
+ }
+
+ delete f;
+ break;
+
+ default:
+ break;
+ }
+ }
+#endif
+
+ NumberFormat* f = NULL;
+ DecimalFormatSymbols* symbolsToAdopt = NULL;
+ UnicodeString pattern;
+ UResourceBundle *resource = ures_open(NULL, desiredLocale.getName(), &status);
+ NumberingSystem *ns = NULL;
+ UBool deleteSymbols = TRUE;
+ UHashtable * cache = NULL;
+ int32_t hashKey;
+ UBool getCache = FALSE;
+ UBool deleteNS = FALSE;
+
+ if (U_FAILURE(status)) {
+ // We don't appear to have resource data available -- use the last-resort data
+ status = U_USING_FALLBACK_WARNING;
+ // When the data is unavailable, and locale isn't passed in, last resort data is used.
+ symbolsToAdopt = new DecimalFormatSymbols(status);
+
+ // Creates a DecimalFormat instance with the last resort number patterns.
+ pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
+ }
+ else {
+ // Loads the decimal symbols of the desired locale.
+ symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
+
+ int32_t patLen = 0;
+
+ /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
+ * the pattern is the same as the pattern of CURRENCYSTYLE
+ * but by replacing the single currency sign with
+ * double currency sign or triple currency sign.
+ */
+ int styleInNumberPattern = ((style == kIsoCurrencyStyle ||
+ style == kPluralCurrencyStyle) ?
+ kCurrencyStyle : style);
+
+ 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);
+
+ const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[styleInNumberPattern], &patLen, &status);
+
+ // Creates the specified decimal format style of the desired locale.
+ pattern.setTo(TRUE, patResStr, patLen);
+ }
+ if (U_FAILURE(status) || symbolsToAdopt == NULL) {
+ goto cleanup;
+ }
+ if(style==kCurrencyStyle || style == kIsoCurrencyStyle){
+ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
+ if(currPattern!=NULL){
+ pattern.setTo(currPattern, u_strlen(currPattern));
+ }
+ }
+
+ // Use numbering system cache hashtable
+ UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache);
+ if (getCache) {
+ umtx_lock(&nscacheMutex);
+ cache = NumberingSystem_cache;
+ umtx_unlock(&nscacheMutex);
+ }
+
+ // Check cache we got, create if non-existant
+ status = U_ZERO_ERROR;
+ if (cache == NULL) {
+ cache = uhash_open(uhash_hashLong,
+ uhash_compareLong,
+ NULL,
+ &status);
+
+ if (cache == NULL || U_FAILURE(status)) {
+ // cache not created - out of memory
+ cache = NULL;
+ }
+ else {
+ // cache created
+ uhash_setValueDeleter(cache, deleteNumberingSystem);
+
+ // set final NumberingSystem_cache value
+ UHashtable* h = NULL;
+
+ UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache);
+ if (getCache) {
+ umtx_lock(&nscacheMutex);
+ h = NumberingSystem_cache;
+ umtx_unlock(&nscacheMutex);
+ }
+ if (h == NULL) {
+ umtx_lock(&nscacheMutex);
+ NumberingSystem_cache = h = cache;
+ cache = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
+ umtx_unlock(&nscacheMutex);
+ }
+
+ if(cache != NULL) {
+ uhash_close(cache);
+ }
+ cache = h;
+ }
+ }
+
+ // Get cached numbering system
+ if (cache != NULL) {
+ hashKey = desiredLocale.hashCode();
+
+ umtx_lock(&nscacheMutex);
+ ns = (NumberingSystem *)uhash_iget(cache, hashKey);
+ if (ns == NULL) {
+ ns = NumberingSystem::createInstance(desiredLocale,status);
+ uhash_iput(cache, hashKey, (void*)ns, &status);
+ }
+ umtx_unlock(&nscacheMutex);
+ }
+ else {
+ ns = NumberingSystem::createInstance(desiredLocale,status);
+ deleteNS = TRUE;
+ }
+
+ // check results of getting a numbering system
+ if ((ns == NULL) || (U_FAILURE(status))) {
+ goto cleanup;
+ }
+
+ 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 ) {
+ char nsLocID[ULOC_FULLNAME_CAPACITY];
+
+ nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV);
+ nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1);
+ nsRuleSetName.setTo(nsDesc,lastSlash+1);
+
+ nsLoc = Locale::createFromName(nsLocID);
+
+ 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 (U_FAILURE(status) || r == NULL) {
+ goto cleanup;
+ }
+ r->setDefaultRuleSet(nsRuleSetName,status);
+ f = (NumberFormat *) r;
+
+ } else {
+ // replace single currency sign in the pattern with double currency sign
+ // if the style is kIsoCurrencyStyle
+ if (style == kIsoCurrencyStyle) {
+ pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign);
+ }
+
+ f = new DecimalFormat(pattern, symbolsToAdopt, style, status);
+ if (U_FAILURE(status) || f == NULL) {
+ goto cleanup;
+ }
+ deleteSymbols = FALSE;
+ }
+
+ f->setLocaleIDs(ures_getLocaleByType(resource, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(resource, ULOC_ACTUAL_LOCALE, &status));
+
+cleanup:
+ ures_close(resource);
+
+ if (deleteNS && ns) {
+ delete ns;
+ }
+
+ if (U_FAILURE(status)) {
+ /* If f exists, then it will delete the symbols */
+ if (f==NULL) {
+ delete symbolsToAdopt;
+ }
+ else {
+ delete f;
+ }
+ return NULL;
+ }
+ if (f == NULL || symbolsToAdopt == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ f = NULL;
+ }
+ if (deleteSymbols && symbolsToAdopt != NULL) {
+ delete symbolsToAdopt;
+ }
+ return f;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/numsys.cpp b/Build/source/libs/icu/icu-4.6/i18n/numsys.cpp
new file mode 100644
index 00000000000..534ed156cef
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/olsontz.cpp b/Build/source/libs/icu/icu-4.6/i18n/olsontz.cpp
new file mode 100644
index 00000000000..b9b2e0507d8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/olsontz.cpp
@@ -0,0 +1,1056 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2010, 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
+
+#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() {
+ 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,
+ UErrorCode& ec) :
+ 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);
+ }
+
+ 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) {
+ 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.6/i18n/olsontz.h b/Build/source/libs/icu/icu-4.6/i18n/olsontz.h
new file mode 100644
index 00000000000..d997e2665e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/olsontz.h
@@ -0,0 +1,427 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2010, 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 ec input-output error code
+ */
+ OlsonTimeZone(const UResourceBundle* top,
+ const UResourceBundle* res, UErrorCode& ec);
+
+ /**
+ * Copy constructor
+ */
+ OlsonTimeZone(const OlsonTimeZone& other);
+
+ /**
+ * Destructor
+ */
+ virtual ~OlsonTimeZone();
+
+ /**
+ * Assignment operator
+ */
+ OlsonTimeZone& operator=(const OlsonTimeZone& other);
+
+ /**
+ * Returns true if the two TimeZone objects are equal.
+ */
+ virtual UBool operator==(const TimeZone& other) const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual TimeZone* clone() const;
+
+ /**
+ * TimeZone API.
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * TimeZone API.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * TimeZone API. Do not call this; prefer getOffset(UDate,...).
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month,
+ int32_t day, uint8_t dayOfWeek,
+ int32_t millis, UErrorCode& ec) const;
+
+ /**
+ * TimeZone API. Do not call this; prefer getOffset(UDate,...).
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month,
+ int32_t day, uint8_t dayOfWeek,
+ int32_t millis, int32_t monthLength,
+ UErrorCode& ec) const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const;
+
+ /**
+ * BasicTimeZone API.
+ */
+ virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/;
+
+ /**
+ * TimeZone API. This method has no effect since objects of this
+ * class are quasi-immutable (the base class allows the ID to be
+ * changed).
+ */
+ virtual void setRawOffset(int32_t offsetMillis);
+
+ /**
+ * TimeZone API. For a historical zone, the raw offset can change
+ * over time, so this API is not useful. In order to approximate
+ * expected behavior, this method returns the raw offset for the
+ * current moment in time.
+ */
+ virtual int32_t getRawOffset() const;
+
+ /**
+ * TimeZone API. For a historical zone, whether DST is used or
+ * not varies over time. In order to approximate expected
+ * behavior, this method returns TRUE if DST is observed at any
+ * point in the current year.
+ */
+ virtual UBool useDaylightTime() const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& ec) const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual int32_t getDSTSavings() const;
+
+ /**
+ * TimeZone API. Also comare historic transitions.
+ */
+ virtual UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * BasicTimeZone API.
+ * Gets the first time zone transition after the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the first transition after the base time.
+ * @return TRUE if the transition is found.
+ */
+ virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * BasicTimeZone API.
+ * Gets the most recent time zone transition before the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the most recent transition before the base time.
+ * @return TRUE if the transition is found.
+ */
+ virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * BasicTimeZone API.
+ * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+ * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+ * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value.
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ */
+ virtual int32_t countTransitionRules(UErrorCode& status) /*const*/;
+
+ /**
+ * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+ * which represent time transitions for this time zone. On successful return,
+ * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+ * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+ * instances up to the size specified by trscount. The results are referencing the
+ * rule instance held by this time zone instance. Therefore, after this time zone
+ * is destructed, they are no longer available.
+ * @param initial Receives the initial timezone rule
+ * @param trsrules Receives the timezone transition rules
+ * @param trscount On input, specify the size of the array 'transitions' receiving
+ * the timezone transition rules. On output, actual number of
+ * rules filled in the array will be set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
+
+private:
+ /**
+ * Default constructor. Creates a time zone with an empty ID and
+ * a fixed GMT offset of zero.
+ */
+ OlsonTimeZone();
+
+private:
+
+ void constructEmpty();
+
+ void getHistoricalOffset(UDate date, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
+ int32_t& rawoff, int32_t& dstoff) const;
+
+ 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;
+
+ /* 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];
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // OLSONTZ_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/persncal.cpp b/Build/source/libs/icu/icu-4.6/i18n/persncal.cpp
new file mode 100644
index 00000000000..51303417aa9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/persncal.h b/Build/source/libs/icu/icu-4.6/i18n/persncal.h
new file mode 100644
index 00000000000..b926da5ef25
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/plurfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp
new file mode 100644
index 00000000000..0464cf57c66
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp
@@ -0,0 +1,537 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+*******************************************************************************
+*/
+
+
+#include "unicode/utypes.h"
+#include "unicode/plurfmt.h"
+#include "unicode/plurrule.h"
+#include "plurrule_impl.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+U_CDECL_BEGIN
+static void U_CALLCONV
+deleteHashStrings(void *obj) {
+ delete (UnicodeString *)obj;
+}
+U_CDECL_END
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralFormat)
+
+#define MAX_KEYWORD_SIZE 30
+
+PluralFormat::PluralFormat(UErrorCode& status) {
+ init(NULL, Locale::getDefault(), status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc, UErrorCode& status) {
+ init(NULL, loc, status);
+}
+
+PluralFormat::PluralFormat(const PluralRules& rules, UErrorCode& status) {
+ init(&rules, Locale::getDefault(), status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc, const PluralRules& rules, UErrorCode& status) {
+ init(&rules, loc, status);
+}
+
+PluralFormat::PluralFormat(const UnicodeString& pat, UErrorCode& status) {
+ init(NULL, Locale::getDefault(), status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc, const UnicodeString& pat, UErrorCode& status) {
+ init(NULL, loc, status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const PluralRules& rules, const UnicodeString& pat, UErrorCode& status) {
+ init(&rules, Locale::getDefault(), status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc, const PluralRules& rules, const UnicodeString& pat, UErrorCode& status) {
+ init(&rules, loc, status);
+ applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const PluralFormat& other) : Format(other) {
+ UErrorCode status = U_ZERO_ERROR;
+ locale = other.locale;
+ pluralRules = other.pluralRules->clone();
+ pattern = other.pattern;
+ copyHashtable(other.fParsedValuesHash, status);
+ if (U_FAILURE(status)) {
+ delete pluralRules;
+ pluralRules = NULL;
+ return;
+ }
+ numberFormat=NumberFormat::createInstance(locale, status);
+ if (U_FAILURE(status)) {
+ delete pluralRules;
+ pluralRules = NULL;
+ delete fParsedValuesHash;
+ fParsedValuesHash = NULL;
+ return;
+ }
+ replacedNumberFormat=other.replacedNumberFormat;
+}
+
+PluralFormat::~PluralFormat() {
+ delete pluralRules;
+ delete fParsedValuesHash;
+ delete numberFormat;
+}
+
+void
+PluralFormat::init(const PluralRules* rules, const Locale& curLocale, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ locale = curLocale;
+ if ( rules==NULL) {
+ pluralRules = PluralRules::forLocale(locale, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ else {
+ pluralRules = rules->clone();
+ }
+ fParsedValuesHash=NULL;
+ pattern.remove();
+ numberFormat= NumberFormat::createInstance(curLocale, status);
+ if (U_FAILURE(status)) {
+ delete pluralRules;
+ pluralRules = NULL;
+ return;
+ }
+ replacedNumberFormat=NULL;
+}
+
+void
+PluralFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ this->pattern = newPattern;
+ UnicodeString token;
+ int32_t braceCount=0;
+ fmtToken type;
+ UBool spaceIncluded=FALSE;
+
+ if (fParsedValuesHash==NULL) {
+ fParsedValuesHash = new Hashtable(TRUE, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fParsedValuesHash->setValueDeleter(deleteHashStrings);
+ }
+
+ UBool getKeyword=TRUE;
+ UnicodeString hashKeyword;
+ UnicodeString *hashPattern;
+
+ for (int32_t i=0; i<pattern.length(); ++i) {
+ UChar ch=pattern.charAt(i);
+
+ if ( !inRange(ch, type) ) {
+ if (getKeyword) {
+ status = U_ILLEGAL_CHARACTER;
+ return;
+ }
+ else {
+ token += ch;
+ continue;
+ }
+ }
+ switch (type) {
+ case tSpace:
+ if (token.length()==0) {
+ continue;
+ }
+ if (getKeyword) {
+ // space after keyword
+ spaceIncluded = TRUE;
+ }
+ else {
+ token += ch;
+ }
+ break;
+ case tLeftBrace:
+ if ( getKeyword ) {
+ if (fParsedValuesHash->get(token)!= NULL) {
+ status = U_DUPLICATE_KEYWORD;
+ return;
+ }
+ if (token.length()==0) {
+ status = U_PATTERN_SYNTAX_ERROR;
+ return;
+ }
+ if (!pluralRules->isKeyword(token)) {
+ status = U_UNDEFINED_KEYWORD;
+ return;
+ }
+ hashKeyword = token;
+ getKeyword = FALSE;
+ token.remove();
+ }
+ else {
+ if (braceCount==0) {
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ else {
+ token += ch;
+ }
+ }
+ braceCount++;
+ spaceIncluded = FALSE;
+ break;
+ case tRightBrace:
+ if ( getKeyword ) {
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ else {
+ hashPattern = new UnicodeString(token);
+ fParsedValuesHash->put(hashKeyword, hashPattern, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ braceCount--;
+ if ( braceCount==0 ) {
+ getKeyword=TRUE;
+ hashKeyword.remove();
+ hashPattern=NULL;
+ token.remove();
+ }
+ else {
+ token += ch;
+ }
+ }
+ spaceIncluded = FALSE;
+ break;
+ case tLetter:
+ case tNumberSign:
+ if (spaceIncluded) {
+ status = U_PATTERN_SYNTAX_ERROR;
+ return;
+ }
+ default:
+ token+=ch;
+ break;
+ }
+ }
+ if ( checkSufficientDefinition() ) {
+ return;
+ }
+ else {
+ status = U_DEFAULT_KEYWORD_MISSING;
+ return;
+ }
+}
+
+UnicodeString&
+PluralFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return appendTo;
+ int32_t number;
+
+ switch (obj.getType())
+ {
+ case Formattable::kDouble:
+ return format((int32_t)obj.getDouble(), appendTo, pos, status);
+ break;
+ case Formattable::kLong:
+ number = (int32_t)obj.getLong();
+ return format(number, appendTo, pos, status);
+ break;
+ case Formattable::kInt64:
+ return format((int32_t)obj.getInt64(), appendTo, pos, status);
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+}
+
+UnicodeString
+PluralFormat::format(int32_t number, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ FieldPosition fpos(0);
+ UnicodeString result;
+
+ return format(number, result, fpos, status);
+}
+
+UnicodeString
+PluralFormat::format(double number, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ 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 (fParsedValuesHash==NULL) {
+ if ( replacedNumberFormat== NULL ) {
+ return numberFormat->format(number, appendTo, pos);
+ }
+ else {
+ replacedNumberFormat->format(number, appendTo, pos);
+ }
+ }
+ UnicodeString selectedRule = pluralRules->select(number);
+ UnicodeString *selectedPattern = (UnicodeString *)fParsedValuesHash->get(selectedRule);
+ if (selectedPattern==NULL) {
+ selectedPattern = (UnicodeString *)fParsedValuesHash->get(pluralRules->getKeywordOther());
+ }
+ appendTo = insertFormattedNumber(number, *selectedPattern, appendTo, pos);
+
+ return appendTo;
+}
+
+UnicodeString&
+PluralFormat::toPattern(UnicodeString& appendTo) {
+ appendTo+= pattern;
+ return appendTo;
+}
+
+UBool
+PluralFormat::inRange(UChar ch, fmtToken& 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;
+ }
+ switch (ch) {
+ case LEFTBRACE:
+ type = tLeftBrace;
+ return TRUE;
+ case SPACE:
+ type = tSpace;
+ return TRUE;
+ case RIGHTBRACE:
+ type = tRightBrace;
+ return TRUE;
+ case NUMBER_SIGN:
+ type = tNumberSign;
+ return TRUE;
+ default :
+ type = none;
+ return FALSE;
+ }
+}
+
+UBool
+PluralFormat::checkSufficientDefinition() {
+ // Check that at least the default rule is defined.
+ if (fParsedValuesHash==NULL) return FALSE;
+ if (fParsedValuesHash->get(pluralRules->getKeywordOther()) == NULL) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+void
+PluralFormat::setLocale(const Locale& loc, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (pluralRules!=NULL) {
+ delete pluralRules;
+ pluralRules=NULL;
+ }
+ if (fParsedValuesHash!= NULL) {
+ delete fParsedValuesHash;
+ fParsedValuesHash = NULL;
+ }
+ if (numberFormat!=NULL) {
+ delete numberFormat;
+ numberFormat = NULL;
+ replacedNumberFormat=NULL;
+ }
+ init(NULL, loc, status);
+}
+
+void
+PluralFormat::setNumberFormat(const NumberFormat* format, UErrorCode& /*status*/) {
+ // TODO: The copy constructor and assignment op of NumberFormat class are protected.
+ // create a pointer as the workaround.
+ replacedNumberFormat = (NumberFormat *)format;
+}
+
+Format*
+PluralFormat::clone() const
+{
+ return new PluralFormat(*this);
+}
+
+PluralFormat&
+PluralFormat::operator=(const PluralFormat& other) {
+ if (this != &other) {
+ UErrorCode status = U_ZERO_ERROR;
+ delete pluralRules;
+ delete fParsedValuesHash;
+ delete numberFormat;
+ locale = other.locale;
+ pluralRules = other.pluralRules->clone();
+ pattern = other.pattern;
+ copyHashtable(other.fParsedValuesHash, status);
+ if (U_FAILURE(status)) {
+ delete pluralRules;
+ pluralRules = NULL;
+ fParsedValuesHash = NULL;
+ numberFormat = NULL;
+ return *this;
+ }
+ numberFormat=NumberFormat::createInstance(locale, status);
+ if (U_FAILURE(status)) {
+ delete pluralRules;
+ delete fParsedValuesHash;
+ pluralRules = NULL;
+ fParsedValuesHash = NULL;
+ numberFormat = NULL;
+ return *this;
+ }
+ replacedNumberFormat=other.replacedNumberFormat;
+ }
+
+ return *this;
+}
+
+UBool
+PluralFormat::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 PluralFormat. THIS IS IMPORTANT.
+ // Format::operator== guarantees that this cast is safe
+ PluralFormat* fmt = (PluralFormat*)&other;
+ return ((*pluralRules == *(fmt->pluralRules)) &&
+ (*numberFormat == *(fmt->numberFormat)));
+}
+
+UBool
+PluralFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+void
+PluralFormat::parseObject(const UnicodeString& /*source*/,
+ Formattable& /*result*/,
+ ParsePosition& /*pos*/) const
+{
+ // TODO: not yet supported in icu4j and icu4c
+}
+
+UnicodeString
+PluralFormat::insertFormattedNumber(double number,
+ UnicodeString& message,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const {
+ UnicodeString result;
+ int32_t braceStack=0;
+ int32_t startIndex=0;
+
+ if (message.length()==0) {
+ return result;
+ }
+ appendTo = numberFormat->format(number, appendTo, pos);
+ for(int32_t i=0; i<message.length(); ++i) {
+ switch(message.charAt(i)) {
+ case LEFTBRACE:
+ ++braceStack;
+ break;
+ case RIGHTBRACE:
+ --braceStack;
+ break;
+ case NUMBER_SIGN:
+ if (braceStack==0) {
+ result += UnicodeString(message, startIndex, i);
+ result += appendTo;
+ startIndex = i + 1;
+ }
+ break;
+ }
+ }
+ if ( startIndex < message.length() ) {
+ result += UnicodeString(message, startIndex, message.length()-startIndex);
+ }
+ appendTo = result;
+ return result;
+}
+
+void
+PluralFormat::copyHashtable(Hashtable *other, UErrorCode& status) {
+ if (other == NULL || U_FAILURE(status)) {
+ fParsedValuesHash = NULL;
+ return;
+ }
+ fParsedValuesHash = new Hashtable(TRUE, status);
+ if(U_FAILURE(status)){
+ return;
+ }
+ fParsedValuesHash->setValueDeleter(deleteHashStrings);
+ 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;
+ const UHashTok otherKeyToVal = elem->value;
+ UnicodeString* otherValue = (UnicodeString*)otherKeyToVal.pointer;
+ fParsedValuesHash->put(*otherKey, new UnicodeString(*otherValue), status);
+ if(U_FAILURE(status)){
+ return;
+ }
+ }
+}
+
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/plurrule.cpp b/Build/source/libs/icu/icu-4.6/i18n/plurrule.cpp
new file mode 100644
index 00000000000..987bb243f47
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/plurrule.cpp
@@ -0,0 +1,1212 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURRULE.CPP
+*
+* Modification History:
+*
+* Date Name Description
+*******************************************************************************
+*/
+
+
+#include "unicode/uniset.h"
+#include "unicode/utypes.h"
+#include "unicode/ures.h"
+#include "unicode/plurrule.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "hash.h"
+#include "mutex.h"
+#include "plurrule_impl.h"
+#include "putilimp.h"
+#include "ucln_in.h"
+#include "ustrfmt.h"
+#include "locutil.h"
+
+/*
+// TODO(claireho): remove stdio
+#include "stdio.h"
+*/
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+
+#define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
+
+static const UChar PLURAL_KEYWORD_ZERO[] = {LOW_Z,LOW_E,LOW_R,LOW_O, 0};
+static const UChar PLURAL_KEYWORD_ONE[]={LOW_O,LOW_N,LOW_E,0};
+static const UChar PLURAL_KEYWORD_TWO[]={LOW_T,LOW_W,LOW_O,0};
+static const UChar PLURAL_KEYWORD_FEW[]={LOW_F,LOW_E,LOW_W,0};
+static const UChar PLURAL_KEYWORD_MANY[]={LOW_M,LOW_A,LOW_N,LOW_Y,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)
+{
+ 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(new RuleParser())
+{
+ *this=other;
+}
+
+PluralRules::~PluralRules() {
+ delete mRules;
+ delete mParser;
+}
+
+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();
+ }
+
+ 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)) {
+ 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)) return NULL;
+
+ return nameEnumerator;
+}
+
+
+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;
+ UBool sameList = TRUE;
+ const UnicodeString *ptrKeyword;
+ UErrorCode status= U_ZERO_ERROR;
+
+ if ( this == &other ) {
+ return TRUE;
+ }
+ StringEnumeration* myKeywordList = getKeywords(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ StringEnumeration* otherKeywordList =other.getKeywords(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ if (myKeywordList->count(status)!=otherKeywordList->count(status) ||
+ U_FAILURE(status)) {
+ sameList = FALSE;
+ }
+ else {
+ myKeywordList->reset(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ while (sameList && (ptrKeyword=myKeywordList->snext(status))!=NULL) {
+ if (U_FAILURE(status) || !other.isKeyword(*ptrKeyword)) {
+ sameList = FALSE;
+ }
+ }
+ otherKeywordList->reset(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ while (sameList && (ptrKeyword=otherKeywordList->snext(status))!=NULL) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (!this->isKeyword(*ptrKeyword)) {
+ sameList = FALSE;
+ }
+ }
+ delete myKeywordList;
+ delete otherKeywordList;
+ if (!sameList) {
+ 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();
+ }
+ 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;
+ }
+}
+
+
+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;
+
+ 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;
+ }
+}
+
+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;
+}
+
+
+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() {
+ UErrorCode err=U_ZERO_ERROR;
+ const UnicodeString idStart=UNICODE_STRING_SIMPLE("[[a-z]]");
+ const UnicodeString idContinue=UNICODE_STRING_SIMPLE("[[a-z][A-Z][_][0-9]]");
+ idStartFilter = new UnicodeSet(idStart, err);
+ idContinueFilter = new UnicodeSet(idContinue, err);
+}
+
+RuleParser::~RuleParser() {
+ delete idStartFilter;
+ delete idContinueFilter;
+}
+
+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) {
+ if ( token.length()==0 ) {
+ return FALSE;
+ }
+ if ( idStartFilter->contains(token.charAt(0) )==TRUE ) {
+ int32_t i;
+ for (i=1; i< token.length(); i++) {
+ if (idContinueFilter->contains(token.charAt(i))== FALSE) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode& status) :
+fKeywordNames(status)
+{
+ RuleChain *node=header;
+ UBool addKeywordOther=true;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ pos=0;
+ fKeywordNames.removeAllElements();
+ 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);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+}
+
+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() {
+ UnicodeString *s;
+ for (int32_t i=0; i<fKeywordNames.size(); ++i) {
+ if ((s=(UnicodeString *)fKeywordNames.elementAt(i))!=NULL) {
+ delete s;
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/plurrule_impl.h b/Build/source/libs/icu/icu-4.6/i18n/plurrule_impl.h
new file mode 100644
index 00000000000..82f79ca9f2f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/plurrule_impl.h
@@ -0,0 +1,221 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURRULE_IMPL.H
+*
+*******************************************************************************
+*/
+
+
+#ifndef PLURRULE_IMPLE
+#define PLURRULE_IMPLE
+
+/**
+ * \file
+ * \brief C++ API: Defines rules for mapping positive long values onto a small set of keywords.
+ */
+
+#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;
+
+
+class UnicodeSet;
+
+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:
+ UnicodeSet *idStartFilter;
+ UnicodeSet *idContinueFilter;
+
+ 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);
+ 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);
+};
+
+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();
+ 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.6/i18n/quant.cpp b/Build/source/libs/icu/icu-4.6/i18n/quant.cpp
new file mode 100644
index 00000000000..3b48290867f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/quant.h b/Build/source/libs/icu/icu-4.6/i18n/quant.h
new file mode 100644
index 00000000000..79388953172
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/quant.h
@@ -0,0 +1,128 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2001-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 07/26/01 aliu Creation.
+ **********************************************************************
+ */
+#ifndef QUANT_H
+#define QUANT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifunct.h"
+#include "unicode/unimatch.h"
+
+U_NAMESPACE_BEGIN
+
+class Quantifier : public UnicodeFunctor, public UnicodeMatcher {
+
+ public:
+
+ enum { MAX = 0x7FFFFFFF };
+
+ Quantifier(UnicodeFunctor *adoptedMatcher,
+ uint32_t minCount, uint32_t maxCount);
+
+ Quantifier(const Quantifier& o);
+
+ virtual ~Quantifier();
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ * @return the UnicodeMatcher pointer.
+ */
+ virtual UnicodeMatcher* toMatcher() const;
+
+ /**
+ * Implement UnicodeFunctor
+ * @return a copy of the object.
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * Implement UnicodeMatcher
+ * @param text the text to be matched
+ * @param offset on input, the index into text at which to begin
+ * matching. On output, the limit of the matched text. The
+ * number of matched characters is the output value of offset
+ * minus the input value. Offset should always point to the
+ * HIGH SURROGATE (leading code unit) of a pair of surrogates,
+ * both on entry and upon return.
+ * @param limit the limit index of text to be matched. Greater
+ * than offset for a forward direction match, less than offset for
+ * a backward direction match. The last character to be
+ * considered for matching will be text.charAt(limit-1) in the
+ * forward direction or text.charAt(limit+1) in the backward
+ * direction.
+ * @param incremental if TRUE, then assume further characters may
+ * be inserted at limit and check for partial matching. Otherwise
+ * assume the text as given is complete.
+ * @return a match degree value indicating a full match, a partial
+ * match, or a mismatch. If incremental is FALSE then
+ * U_PARTIAL_MATCH should never be returned.
+ */
+ virtual UMatchDegree matches(const Replaceable& text,
+ int32_t& offset,
+ int32_t limit,
+ UBool incremental);
+
+ /**
+ * Implement UnicodeMatcher
+ * @param result Output param to receive the pattern.
+ * @param escapeUnprintable if True then escape the unprintable characters.
+ * @return A reference to 'result'.
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool escapeUnprintable = FALSE) const;
+
+ /**
+ * Implement UnicodeMatcher
+ * @param v the given index value.
+ * @return true if this rule matches the given index value.
+ */
+ virtual UBool matchesIndexValue(uint8_t v) const;
+
+ /**
+ * Implement UnicodeMatcher
+ */
+ virtual void addMatchSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * UnicodeFunctor API
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ private:
+
+ UnicodeFunctor* matcher; // owned
+
+ uint32_t minCount;
+
+ uint32_t maxCount;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/rbnf.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbnf.cpp
new file mode 100644
index 00000000000..b8d392a592b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/rbnf.cpp
@@ -0,0 +1,1615 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 "util.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 && uprv_isRuleWhiteSpace(ch != 0xffff ? ch : *p)) inc();}
+ UBool inList(UChar c, const UChar* list) const {
+ if (*list == SPACE && uprv_isRuleWhiteSpace(c)) return TRUE;
+ while (*list && *list != c) ++list; return *list == c;
+ }
+ void parseError(const char* msg);
+
+ StringLocalizationInfo* doParse(void);
+
+ UChar** nextArray(int32_t& requiredLength);
+ UChar* nextString(void);
+};
+
+#ifdef DEBUG
+#define ERROR(msg) parseError(msg); return NULL;
+#else
+#define ERROR(msg) parseError(NULL); return NULL;
+#endif
+
+
+static const UChar DQUOTE_STOPLIST[] = {
+ QUOTE, 0
+};
+
+static const UChar SQUOTE_STOPLIST[] = {
+ TICK, 0
+};
+
+static const UChar NOQUOTE_STOPLIST[] = {
+ SPACE, COMMA, CLOSE_ANGLE, OPEN_ANGLE, TICK, QUOTE, 0
+};
+
+static void
+DeleteFn(void* p) {
+ uprv_free(p);
+}
+
+StringLocalizationInfo*
+LocDataParser::parse(UChar* _data, int32_t len) {
+ if (U_FAILURE(ec)) {
+ if (_data) uprv_free(_data);
+ return NULL;
+ }
+
+ pe.line = 0;
+ pe.offset = -1;
+ pe.postContext[0] = 0;
+ pe.preContext[0] = 0;
+
+ if (_data == NULL) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ if (len <= 0) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ uprv_free(_data);
+ return NULL;
+ }
+
+ data = _data;
+ e = data + len;
+ p = _data;
+ ch = 0xffff;
+
+ return doParse();
+}
+
+
+StringLocalizationInfo*
+LocDataParser::doParse(void) {
+ skipWhitespace();
+ if (!checkInc(OPEN_ANGLE)) {
+ ERROR("Missing open angle");
+ } else {
+ VArray array(DeleteFn);
+ UBool mightHaveNext = TRUE;
+ int32_t requiredLength = -1;
+ while (mightHaveNext) {
+ mightHaveNext = FALSE;
+ UChar** elem = nextArray(requiredLength);
+ skipWhitespace();
+ UBool haveComma = check(COMMA);
+ if (elem) {
+ array.add(elem, ec);
+ if (haveComma) {
+ inc();
+ mightHaveNext = TRUE;
+ }
+ } else if (haveComma) {
+ ERROR("Unexpected character");
+ }
+ }
+
+ skipWhitespace();
+ if (!checkInc(CLOSE_ANGLE)) {
+ if (check(OPEN_ANGLE)) {
+ ERROR("Missing comma in outer array");
+ } else {
+ ERROR("Missing close angle bracket in outer array");
+ }
+ }
+
+ skipWhitespace();
+ if (p != e) {
+ ERROR("Extra text after close of localization data");
+ }
+
+ array.add(NULL, ec);
+ if (U_SUCCESS(ec)) {
+ int32_t numLocs = array.length() - 2; // subtract first, NULL
+ UChar*** result = (UChar***)array.release();
+
+ return new StringLocalizationInfo(data, result, requiredLength-2, numLocs); // subtract first, NULL
+ }
+ }
+
+ ERROR("Unknown error");
+}
+
+UChar**
+LocDataParser::nextArray(int32_t& requiredLength) {
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+
+ skipWhitespace();
+ if (!checkInc(OPEN_ANGLE)) {
+ ERROR("Missing open angle");
+ }
+
+ VArray array;
+ UBool mightHaveNext = TRUE;
+ while (mightHaveNext) {
+ mightHaveNext = FALSE;
+ UChar* elem = nextString();
+ skipWhitespace();
+ UBool haveComma = check(COMMA);
+ if (elem) {
+ array.add(elem, ec);
+ if (haveComma) {
+ inc();
+ mightHaveNext = TRUE;
+ }
+ } else if (haveComma) {
+ ERROR("Unexpected comma");
+ }
+ }
+ skipWhitespace();
+ if (!checkInc(CLOSE_ANGLE)) {
+ if (check(OPEN_ANGLE)) {
+ ERROR("Missing close angle bracket in inner array");
+ } else {
+ ERROR("Missing comma in inner array");
+ }
+ }
+
+ array.add(NULL, ec);
+ if (U_SUCCESS(ec)) {
+ if (requiredLength == -1) {
+ requiredLength = array.length() + 1;
+ } else if (array.length() != requiredLength) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ ERROR("Array not of required length");
+ }
+
+ return (UChar**)array.release();
+ }
+ ERROR("Unknown Error");
+}
+
+UChar*
+LocDataParser::nextString() {
+ UChar* result = NULL;
+
+ skipWhitespace();
+ if (p < e) {
+ const UChar* terminators;
+ UChar c = *p;
+ UBool haveQuote = c == QUOTE || c == TICK;
+ if (haveQuote) {
+ inc();
+ terminators = c == QUOTE ? DQUOTE_STOPLIST : SQUOTE_STOPLIST;
+ } else {
+ terminators = NOQUOTE_STOPLIST;
+ }
+ UChar* start = p;
+ while (p < e && !inList(*p, terminators)) ++p;
+ if (p == e) {
+ ERROR("Unexpected end of data");
+ }
+
+ UChar x = *p;
+ if (p > start) {
+ ch = x;
+ *p = 0x0; // terminate by writing to data
+ result = start; // just point into data
+ }
+ if (haveQuote) {
+ if (x != c) {
+ ERROR("Missing matching quote");
+ } else if (p == start) {
+ ERROR("Empty string");
+ }
+ inc();
+ } else if (x == OPEN_ANGLE || x == TICK || x == QUOTE) {
+ ERROR("Unexpected character in string");
+ }
+ }
+
+ // ok for there to be no next string
+ return result;
+}
+
+void
+LocDataParser::parseError(const char* /*str*/) {
+ if (!data) {
+ return;
+ }
+
+ const UChar* start = p - U_PARSE_CONTEXT_LEN - 1;
+ if (start < data) {
+ start = data;
+ }
+ for (UChar* x = p; --x >= start;) {
+ if (!*x) {
+ start = x+1;
+ break;
+ }
+ }
+ const UChar* limit = p + U_PARSE_CONTEXT_LEN - 1;
+ if (limit > e) {
+ limit = e;
+ }
+ u_strncpy(pe.preContext, start, (int32_t)(p-start));
+ pe.preContext[p-start] = 0;
+ u_strncpy(pe.postContext, p, (int32_t)(limit-p));
+ pe.postContext[limit-p] = 0;
+ pe.offset = (int32_t)(p - data);
+
+#ifdef DEBUG
+ fprintf(stderr, "%s at or near character %d: ", str, p-data);
+
+ UnicodeString msg;
+ msg.append(start, p - start);
+ msg.append((UChar)0x002f); /* SOLIDUS/SLASH */
+ msg.append(p, limit-p);
+ msg.append("'");
+
+ char buf[128];
+ int32_t len = msg.extract(0, msg.length(), buf, 128);
+ if (len >= 128) {
+ buf[127] = 0;
+ } else {
+ buf[len] = 0;
+ }
+ fprintf(stderr, "%s\n", buf);
+ fflush(stderr);
+#endif
+
+ uprv_free(data);
+ data = NULL;
+ p = NULL;
+ e = NULL;
+
+ if (U_SUCCESS(ec)) {
+ ec = U_PARSE_ERROR;
+ }
+}
+
+//UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringLocalizationInfo)
+
+StringLocalizationInfo*
+StringLocalizationInfo::create(const UnicodeString& info, UParseError& perror, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ int32_t len = info.length();
+ if (len == 0) {
+ return NULL; // no error;
+ }
+
+ UChar* p = (UChar*)uprv_malloc(len * sizeof(UChar));
+ if (!p) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ info.extract(p, len, status);
+ if (!U_FAILURE(status)) {
+ status = U_ZERO_ERROR; // clear warning about non-termination
+ }
+
+ LocDataParser parser(perror, status);
+ return parser.parse(p, len);
+}
+
+StringLocalizationInfo::~StringLocalizationInfo() {
+ for (UChar*** p = (UChar***)data; *p; ++p) {
+ // remaining data is simply pointer into our unicode string data.
+ if (*p) uprv_free(*p);
+ }
+ if (data) uprv_free(data);
+ if (info) uprv_free(info);
+}
+
+
+const UChar*
+StringLocalizationInfo::getRuleSetName(int32_t index) const {
+ if (index >= 0 && index < getNumberOfRuleSets()) {
+ return data[0][index];
+ }
+ return NULL;
+}
+
+const UChar*
+StringLocalizationInfo::getLocaleName(int32_t index) const {
+ if (index >= 0 && index < getNumberOfDisplayLocales()) {
+ return data[index+1][0];
+ }
+ return NULL;
+}
+
+const UChar*
+StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) const {
+ if (localeIndex >= 0 && localeIndex < getNumberOfDisplayLocales() &&
+ ruleIndex >= 0 && ruleIndex < getNumberOfRuleSets()) {
+ return data[localeIndex+1][ruleIndex+1];
+ }
+ return NULL;
+}
+
+// ----------
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
+ const UnicodeString& locs,
+ const Locale& alocale, UParseError& perror, UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(alocale)
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+ , 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
+{
+ 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 (uprv_isRuleWhiteSpace(description.charAt(lpStart))) {
+ ++lpStart;
+ }
+
+ // copy out the lenient-parse rules and delete them
+ // from the description
+ lenientParseRules = new UnicodeString();
+ /* test for NULL */
+ if (lenientParseRules == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ lenientParseRules->setTo(description, lpStart, lpEnd - lpStart);
+
+ description.remove(lp, lpEnd + 1 - lp);
+ }
+ }
+
+ // pre-flight parsing the description and count the number of
+ // rule sets (";%" marks the end of one rule set and the beginning
+ // of the next)
+ int numRuleSets = 0;
+ for (int32_t p = description.indexOf(gSemiPercent); p != -1; p = description.indexOf(gSemiPercent, p)) {
+ ++numRuleSets;
+ ++p;
+ }
+ ++numRuleSets;
+
+ // our rule list is an array of the appropriate size
+ ruleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
+ /* test for NULL */
+ if (ruleSets == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ for (int i = 0; i <= numRuleSets; ++i) {
+ ruleSets[i] = NULL;
+ }
+
+ // divide up the descriptions into individual rule-set descriptions
+ // and store them in a temporary array. At each step, we also
+ // new up a rule set, but all this does is initialize its name
+ // and remove it from its description. We can't actually parse
+ // the rest of the descriptions and finish initializing everything
+ // because we have to know the names and locations of all the rule
+ // sets before we can actually set everything up
+ if(!numRuleSets) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeString* ruleSetDescriptions = new UnicodeString[numRuleSets];
+ 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()
+ && uprv_isRuleWhiteSpace(description.charAt(start))) {
+ ++start;
+ }
+
+ // locate the next semicolon in the text and copy the text from
+ // our current position up to that semicolon into the result
+ int32_t p = description.indexOf(gSemiColon, start);
+ if (p == -1) {
+ // or if we don't find a semicolon, just copy the rest of
+ // the string into the result
+ result.append(description, start, description.length() - start);
+ start = -1;
+ }
+ else if (p < description.length()) {
+ result.append(description, start, p + 1 - start);
+ start = p + 1;
+ }
+
+ // when we get here, we've seeked off the end of the sring, and
+ // we terminate the loop (we continue until *start* is -1 rather
+ // than until *p* is -1, because otherwise we'd miss the last
+ // rule in the description)
+ else {
+ start = -1;
+ }
+ }
+
+ description.setTo(result);
+}
+
+
+void
+RuleBasedNumberFormat::dispose()
+{
+ if (ruleSets) {
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ delete *p;
+ }
+ uprv_free(ruleSets);
+ ruleSets = NULL;
+ }
+
+#if !UCONFIG_NO_COLLATION
+ delete collator;
+#endif
+ collator = NULL;
+
+ delete decimalFormatSymbols;
+ decimalFormatSymbols = NULL;
+
+ delete lenientParseRules;
+ lenientParseRules = NULL;
+
+ if (localizations) localizations = localizations->unref();
+}
+
+
+//-----------------------------------------------------------------------
+// package-internal API
+//-----------------------------------------------------------------------
+
+/**
+ * Returns the collator to use for lenient parsing. The collator is lazily created:
+ * this function creates it the first time it's called.
+ * @return The collator to use for lenient parsing, or null if lenient parsing
+ * is turned off.
+*/
+Collator*
+RuleBasedNumberFormat::getCollator() const
+{
+#if !UCONFIG_NO_COLLATION
+ if (!ruleSets) {
+ return NULL;
+ }
+
+ // lazy-evaulate the collator
+ if (collator == NULL && lenient) {
+ // create a default collator based on the formatter's locale,
+ // then pull out that collator's rules, append any additional
+ // rules specified in the description, and create a _new_
+ // collator based on the combinaiton of those rules
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ Collator* temp = Collator::createInstance(locale, status);
+ 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.6/i18n/rbt.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbt.cpp
new file mode 100644
index 00000000000..6041a9245e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt.h b/Build/source/libs/icu/icu-4.6/i18n/rbt.h
new file mode 100644
index 00000000000..d061de6e637
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_data.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbt_data.cpp
new file mode 100644
index 00000000000..beef99231f9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_data.h b/Build/source/libs/icu/icu-4.6/i18n/rbt_data.h
new file mode 100644
index 00000000000..ce833dc26dd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_pars.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbt_pars.cpp
new file mode 100644
index 00000000000..483c05476bc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/rbt_pars.cpp
@@ -0,0 +1,1732 @@
+/*
+ **********************************************************************
+ * 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/uobject.h"
+#include "unicode/parseerr.h"
+#include "unicode/parsepos.h"
+#include "unicode/putil.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/uniset.h"
+#include "cstring.h"
+#include "funcrepl.h"
+#include "hash.h"
+#include "quant.h"
+#include "rbt.h"
+#include "rbt_data.h"
+#include "rbt_pars.h"
+#include "rbt_rule.h"
+#include "strmatch.h"
+#include "strrepl.h"
+#include "unicode/symtable.h"
+#include "tridpars.h"
+#include "uvector.h"
+#include "hash.h"
+#include "util.h"
+#include "cmemory.h"
+#include "uprops.h"
+#include "putilimp.h"
+
+// Operators
+#define VARIABLE_DEF_OP ((UChar)0x003D) /*=*/
+#define FORWARD_RULE_OP ((UChar)0x003E) /*>*/
+#define REVERSE_RULE_OP ((UChar)0x003C) /*<*/
+#define FWDREV_RULE_OP ((UChar)0x007E) /*~*/ // internal rep of <> op
+
+// Other special characters
+#define QUOTE ((UChar)0x0027) /*'*/
+#define ESCAPE ((UChar)0x005C) /*\*/
+#define END_OF_RULE ((UChar)0x003B) /*;*/
+#define RULE_COMMENT_CHAR ((UChar)0x0023) /*#*/
+
+#define SEGMENT_OPEN ((UChar)0x0028) /*(*/
+#define SEGMENT_CLOSE ((UChar)0x0029) /*)*/
+#define CONTEXT_ANTE ((UChar)0x007B) /*{*/
+#define CONTEXT_POST ((UChar)0x007D) /*}*/
+#define CURSOR_POS ((UChar)0x007C) /*|*/
+#define CURSOR_OFFSET ((UChar)0x0040) /*@*/
+#define ANCHOR_START ((UChar)0x005E) /*^*/
+#define KLEENE_STAR ((UChar)0x002A) /***/
+#define ONE_OR_MORE ((UChar)0x002B) /*+*/
+#define ZERO_OR_ONE ((UChar)0x003F) /*?*/
+
+#define DOT ((UChar)46) /*.*/
+
+static const UChar DOT_SET[] = { // "[^[:Zp:][:Zl:]\r\n$]";
+ 91, 94, 91, 58, 90, 112, 58, 93, 91, 58, 90,
+ 108, 58, 93, 92, 114, 92, 110, 36, 93, 0
+};
+
+// A function is denoted &Source-Target/Variant(text)
+#define FUNCTION ((UChar)38) /*&*/
+
+// Aliases for some of the syntax characters. These are provided so
+// transliteration rules can be expressed in XML without clashing with
+// XML syntax characters '<', '>', and '&'.
+#define ALT_REVERSE_RULE_OP ((UChar)0x2190) // Left Arrow
+#define ALT_FORWARD_RULE_OP ((UChar)0x2192) // Right Arrow
+#define ALT_FWDREV_RULE_OP ((UChar)0x2194) // Left Right Arrow
+#define ALT_FUNCTION ((UChar)0x2206) // Increment (~Greek Capital Delta)
+
+// Special characters disallowed at the top level
+static const UChar ILLEGAL_TOP[] = {41,0}; // ")"
+
+// Special characters disallowed within a segment
+static const UChar ILLEGAL_SEG[] = {123,125,124,64,0}; // "{}|@"
+
+// Special characters disallowed within a function argument
+static const UChar ILLEGAL_FUNC[] = {94,40,46,42,43,63,123,125,124,64,0}; // "^(.*+?{}|@"
+
+// By definition, the ANCHOR_END special character is a
+// trailing SymbolTable.SYMBOL_REF character.
+// private static final char ANCHOR_END = '$';
+
+static const UChar gOPERATORS[] = { // "=><"
+ VARIABLE_DEF_OP, FORWARD_RULE_OP, REVERSE_RULE_OP,
+ ALT_FORWARD_RULE_OP, ALT_REVERSE_RULE_OP, ALT_FWDREV_RULE_OP,
+ 0
+};
+
+static const UChar HALF_ENDERS[] = { // "=><;"
+ VARIABLE_DEF_OP, FORWARD_RULE_OP, REVERSE_RULE_OP,
+ ALT_FORWARD_RULE_OP, ALT_REVERSE_RULE_OP, ALT_FWDREV_RULE_OP,
+ END_OF_RULE,
+ 0
+};
+
+// These are also used in Transliterator::toRules()
+static const int32_t ID_TOKEN_LEN = 2;
+static const UChar ID_TOKEN[] = { 0x3A, 0x3A }; // ':', ':'
+
+/*
+commented out until we do real ::BEGIN/::END functionality
+static const int32_t BEGIN_TOKEN_LEN = 5;
+static const UChar BEGIN_TOKEN[] = { 0x42, 0x45, 0x47, 0x49, 0x4e }; // 'BEGIN'
+
+static const int32_t END_TOKEN_LEN = 3;
+static const UChar END_TOKEN[] = { 0x45, 0x4e, 0x44 }; // 'END'
+*/
+
+U_NAMESPACE_BEGIN
+
+//----------------------------------------------------------------------
+// BEGIN ParseData
+//----------------------------------------------------------------------
+
+/**
+ * This class implements the SymbolTable interface. It is used
+ * during parsing to give UnicodeSet access to variables that
+ * have been defined so far. Note that it uses variablesVector,
+ * _not_ data.setVariables.
+ */
+class ParseData : public UMemory, public SymbolTable {
+public:
+ const TransliterationRuleData* data; // alias
+
+ const UVector* variablesVector; // alias
+
+ const Hashtable* variableNames; // alias
+
+ ParseData(const TransliterationRuleData* data = 0,
+ const UVector* variablesVector = 0,
+ const Hashtable* variableNames = 0);
+
+ virtual const UnicodeString* lookup(const UnicodeString& s) const;
+
+ virtual const UnicodeFunctor* lookupMatcher(UChar32 ch) const;
+
+ virtual UnicodeString parseReference(const UnicodeString& text,
+ ParsePosition& pos, int32_t limit) const;
+ /**
+ * Return true if the given character is a matcher standin or a plain
+ * character (non standin).
+ */
+ UBool isMatcher(UChar32 ch);
+
+ /**
+ * Return true if the given character is a replacer standin or a plain
+ * character (non standin).
+ */
+ UBool isReplacer(UChar32 ch);
+
+private:
+ ParseData(const ParseData &other); // forbid copying of this class
+ ParseData &operator=(const ParseData &other); // forbid copying of this class
+};
+
+ParseData::ParseData(const TransliterationRuleData* d,
+ const UVector* sets,
+ const Hashtable* vNames) :
+ data(d), variablesVector(sets), variableNames(vNames) {}
+
+/**
+ * Implement SymbolTable API.
+ */
+const UnicodeString* ParseData::lookup(const UnicodeString& name) const {
+ return (const UnicodeString*) variableNames->get(name);
+}
+
+/**
+ * Implement SymbolTable API.
+ */
+const UnicodeFunctor* ParseData::lookupMatcher(UChar32 ch) const {
+ // Note that we cannot use data.lookupSet() because the
+ // set array has not been constructed yet.
+ const UnicodeFunctor* set = NULL;
+ int32_t i = ch - data->variablesBase;
+ if (i >= 0 && i < variablesVector->size()) {
+ int32_t i = ch - data->variablesBase;
+ set = (i < variablesVector->size()) ?
+ (UnicodeFunctor*) variablesVector->elementAt(i) : 0;
+ }
+ return set;
+}
+
+/**
+ * Implement SymbolTable API. Parse out a symbol reference
+ * name.
+ */
+UnicodeString ParseData::parseReference(const UnicodeString& text,
+ ParsePosition& pos, int32_t limit) const {
+ int32_t start = pos.getIndex();
+ int32_t i = start;
+ UnicodeString result;
+ while (i < limit) {
+ UChar c = text.charAt(i);
+ if ((i==start && !u_isIDStart(c)) || !u_isIDPart(c)) {
+ break;
+ }
+ ++i;
+ }
+ if (i == start) { // No valid name chars
+ return result; // Indicate failure with empty string
+ }
+ pos.setIndex(i);
+ text.extractBetween(start, i, result);
+ return result;
+}
+
+UBool ParseData::isMatcher(UChar32 ch) {
+ // Note that we cannot use data.lookup() because the
+ // set array has not been constructed yet.
+ int32_t i = ch - data->variablesBase;
+ if (i >= 0 && i < variablesVector->size()) {
+ UnicodeFunctor *f = (UnicodeFunctor*) variablesVector->elementAt(i);
+ return f != NULL && f->toMatcher() != NULL;
+ }
+ return TRUE;
+}
+
+/**
+ * Return true if the given character is a replacer standin or a plain
+ * character (non standin).
+ */
+UBool ParseData::isReplacer(UChar32 ch) {
+ // Note that we cannot use data.lookup() because the
+ // set array has not been constructed yet.
+ int i = ch - data->variablesBase;
+ if (i >= 0 && i < variablesVector->size()) {
+ UnicodeFunctor *f = (UnicodeFunctor*) variablesVector->elementAt(i);
+ return f != NULL && f->toReplacer() != NULL;
+ }
+ return TRUE;
+}
+
+//----------------------------------------------------------------------
+// BEGIN RuleHalf
+//----------------------------------------------------------------------
+
+/**
+ * A class representing one side of a rule. This class knows how to
+ * parse half of a rule. It is tightly coupled to the method
+ * RuleBasedTransliterator.Parser.parseRule().
+ */
+class RuleHalf : public UMemory {
+
+public:
+
+ UnicodeString text;
+
+ int32_t cursor; // position of cursor in text
+ int32_t ante; // position of ante context marker '{' in text
+ int32_t post; // position of post context marker '}' in text
+
+ // Record the offset to the cursor either to the left or to the
+ // right of the key. This is indicated by characters on the output
+ // side that allow the cursor to be positioned arbitrarily within
+ // the matching text. For example, abc{def} > | @@@ xyz; changes
+ // def to xyz and moves the cursor to before abc. Offset characters
+ // must be at the start or end, and they cannot move the cursor past
+ // the ante- or postcontext text. Placeholders are only valid in
+ // output text. The length of the ante and post context is
+ // determined at runtime, because of supplementals and quantifiers.
+ int32_t cursorOffset; // only nonzero on output side
+
+ // Position of first CURSOR_OFFSET on _right_. This will be -1
+ // for |@, -2 for |@@, etc., and 1 for @|, 2 for @@|, etc.
+ int32_t cursorOffsetPos;
+
+ UBool anchorStart;
+ UBool anchorEnd;
+
+ /**
+ * The segment number from 1..n of the next '(' we see
+ * during parsing; 1-based.
+ */
+ int32_t nextSegmentNumber;
+
+ TransliteratorParser& parser;
+
+ //--------------------------------------------------
+ // Methods
+
+ RuleHalf(TransliteratorParser& parser);
+ ~RuleHalf();
+
+ int32_t parse(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status);
+
+ int32_t parseSection(const UnicodeString& rule, int32_t pos, int32_t limit,
+ UnicodeString& buf,
+ const UnicodeString& illegal,
+ UBool isSegment,
+ UErrorCode& status);
+
+ /**
+ * Remove context.
+ */
+ void removeContext();
+
+ /**
+ * Return true if this half looks like valid output, that is, does not
+ * contain quantifiers or other special input-only elements.
+ */
+ UBool isValidOutput(TransliteratorParser& parser);
+
+ /**
+ * Return true if this half looks like valid input, that is, does not
+ * contain functions or other special output-only elements.
+ */
+ UBool isValidInput(TransliteratorParser& parser);
+
+ int syntaxError(UErrorCode code,
+ const UnicodeString& rule,
+ int32_t start,
+ UErrorCode& status) {
+ return parser.syntaxError(code, rule, start, status);
+ }
+
+private:
+ // Disallowed methods; no impl.
+ RuleHalf(const RuleHalf&);
+ RuleHalf& operator=(const RuleHalf&);
+};
+
+RuleHalf::RuleHalf(TransliteratorParser& p) :
+ parser(p)
+{
+ cursor = -1;
+ ante = -1;
+ post = -1;
+ cursorOffset = 0;
+ cursorOffsetPos = 0;
+ anchorStart = anchorEnd = FALSE;
+ nextSegmentNumber = 1;
+}
+
+RuleHalf::~RuleHalf() {
+}
+
+/**
+ * Parse one side of a rule, stopping at either the limit,
+ * the END_OF_RULE character, or an operator.
+ * @return the index after the terminating character, or
+ * if limit was reached, limit
+ */
+int32_t RuleHalf::parse(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status) {
+ int32_t start = pos;
+ text.truncate(0);
+ pos = parseSection(rule, pos, limit, text, ILLEGAL_TOP, FALSE, status);
+
+ if (cursorOffset > 0 && cursor != cursorOffsetPos) {
+ return syntaxError(U_MISPLACED_CURSOR_OFFSET, rule, start, status);
+ }
+
+ return pos;
+}
+
+/**
+ * Parse a section of one side of a rule, stopping at either
+ * the limit, the END_OF_RULE character, an operator, or a
+ * segment close character. This method parses both a
+ * top-level rule half and a segment within such a rule half.
+ * It calls itself recursively to parse segments and nested
+ * segments.
+ * @param buf buffer into which to accumulate the rule pattern
+ * characters, either literal characters from the rule or
+ * standins for UnicodeMatcher objects including segments.
+ * @param illegal the set of special characters that is illegal during
+ * this parse.
+ * @param isSegment if true, then we've already seen a '(' and
+ * pos on entry points right after it. Accumulate everything
+ * up to the closing ')', put it in a segment matcher object,
+ * generate a standin for it, and add the standin to buf. As
+ * a side effect, update the segments vector with a reference
+ * to the segment matcher. This works recursively for nested
+ * segments. If isSegment is false, just accumulate
+ * characters into buf.
+ * @return the index after the terminating character, or
+ * if limit was reached, limit
+ */
+int32_t RuleHalf::parseSection(const UnicodeString& rule, int32_t pos, int32_t limit,
+ UnicodeString& buf,
+ const UnicodeString& illegal,
+ UBool isSegment, UErrorCode& status) {
+ int32_t start = pos;
+ ParsePosition pp;
+ UnicodeString scratch;
+ UBool done = FALSE;
+ int32_t quoteStart = -1; // Most recent 'single quoted string'
+ int32_t quoteLimit = -1;
+ int32_t varStart = -1; // Most recent $variableReference
+ int32_t varLimit = -1;
+ int32_t bufStart = buf.length();
+
+ while (pos < limit && !done) {
+ // Since all syntax characters are in the BMP, fetching
+ // 16-bit code units suffices here.
+ UChar c = rule.charAt(pos++);
+ if (uprv_isRuleWhiteSpace(c)) {
+ // Ignore whitespace. Note that this is not Unicode
+ // spaces, but Java spaces -- a subset, representing
+ // whitespace likely to be seen in code.
+ continue;
+ }
+ if (u_strchr(HALF_ENDERS, c) != NULL) {
+ if (isSegment) {
+ // Unclosed segment
+ return syntaxError(U_UNCLOSED_SEGMENT, rule, start, status);
+ }
+ break;
+ }
+ if (anchorEnd) {
+ // Text after a presumed end anchor is a syntax err
+ return syntaxError(U_MALFORMED_VARIABLE_REFERENCE, rule, start, status);
+ }
+ if (UnicodeSet::resemblesPattern(rule, pos-1)) {
+ pp.setIndex(pos-1); // Backup to opening '['
+ buf.append(parser.parseSet(rule, pp, status));
+ if (U_FAILURE(status)) {
+ return syntaxError(U_MALFORMED_SET, rule, start, status);
+ }
+ pos = pp.getIndex();
+ continue;
+ }
+ // Handle escapes
+ if (c == ESCAPE) {
+ if (pos == limit) {
+ return syntaxError(U_TRAILING_BACKSLASH, rule, start, status);
+ }
+ UChar32 escaped = rule.unescapeAt(pos); // pos is already past '\\'
+ if (escaped == (UChar32) -1) {
+ return syntaxError(U_MALFORMED_UNICODE_ESCAPE, rule, start, status);
+ }
+ if (!parser.checkVariableRange(escaped)) {
+ return syntaxError(U_VARIABLE_RANGE_OVERLAP, rule, start, status);
+ }
+ buf.append(escaped);
+ continue;
+ }
+ // Handle quoted matter
+ if (c == QUOTE) {
+ int32_t iq = rule.indexOf(QUOTE, pos);
+ if (iq == pos) {
+ buf.append(c); // Parse [''] outside quotes as [']
+ ++pos;
+ } else {
+ /* This loop picks up a run of quoted text of the
+ * form 'aaaa' each time through. If this run
+ * hasn't really ended ('aaaa''bbbb') then it keeps
+ * looping, each time adding on a new run. When it
+ * reaches the final quote it breaks.
+ */
+ quoteStart = buf.length();
+ for (;;) {
+ if (iq < 0) {
+ return syntaxError(U_UNTERMINATED_QUOTE, rule, start, status);
+ }
+ scratch.truncate(0);
+ rule.extractBetween(pos, iq, scratch);
+ buf.append(scratch);
+ pos = iq+1;
+ if (pos < limit && rule.charAt(pos) == QUOTE) {
+ // Parse [''] inside quotes as [']
+ iq = rule.indexOf(QUOTE, pos+1);
+ // Continue looping
+ } else {
+ break;
+ }
+ }
+ quoteLimit = buf.length();
+
+ for (iq=quoteStart; iq<quoteLimit; ++iq) {
+ if (!parser.checkVariableRange(buf.charAt(iq))) {
+ return syntaxError(U_VARIABLE_RANGE_OVERLAP, rule, start, status);
+ }
+ }
+ }
+ continue;
+ }
+
+ if (!parser.checkVariableRange(c)) {
+ return syntaxError(U_VARIABLE_RANGE_OVERLAP, rule, start, status);
+ }
+
+ if (illegal.indexOf(c) >= 0) {
+ syntaxError(U_ILLEGAL_CHARACTER, rule, start, status);
+ }
+
+ switch (c) {
+
+ //------------------------------------------------------
+ // Elements allowed within and out of segments
+ //------------------------------------------------------
+ case ANCHOR_START:
+ if (buf.length() == 0 && !anchorStart) {
+ anchorStart = TRUE;
+ } else {
+ return syntaxError(U_MISPLACED_ANCHOR_START,
+ rule, start, status);
+ }
+ break;
+ case SEGMENT_OPEN:
+ {
+ // bufSegStart is the offset in buf to the first
+ // character of the segment we are parsing.
+ int32_t bufSegStart = buf.length();
+
+ // Record segment number now, since nextSegmentNumber
+ // will be incremented during the call to parseSection
+ // if there are nested segments.
+ int32_t segmentNumber = nextSegmentNumber++; // 1-based
+
+ // Parse the segment
+ pos = parseSection(rule, pos, limit, buf, ILLEGAL_SEG, TRUE, status);
+
+ // After parsing a segment, the relevant characters are
+ // in buf, starting at offset bufSegStart. Extract them
+ // into a string matcher, and replace them with a
+ // standin for that matcher.
+ StringMatcher* m =
+ new StringMatcher(buf, bufSegStart, buf.length(),
+ segmentNumber, *parser.curData);
+ 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 (uprv_isRuleWhiteSpace(c)) {
+ // Ignore leading whitespace.
+ continue;
+ }
+ // Skip lines starting with the comment character
+ if (c == RULE_COMMENT_CHAR) {
+ pos = rule.indexOf((UChar)0x000A /*\n*/, pos) + 1;
+ if (pos == 0) {
+ break; // No "\n" found; rest of rule is a commnet
+ }
+ continue; // Either fall out or restart with next line
+ }
+
+ // skip empty rules
+ if (c == END_OF_RULE)
+ continue;
+
+ // keep track of how many rules we've seen
+ ++ruleCount;
+
+ // We've found the start of a rule or ID. c is its first
+ // character, and pos points past c.
+ --pos;
+ // Look for an ID token. Must have at least ID_TOKEN_LEN + 1
+ // chars left.
+ if ((pos + ID_TOKEN_LEN + 1) <= limit &&
+ rule.compare(pos, ID_TOKEN_LEN, ID_TOKEN) == 0) {
+ pos += ID_TOKEN_LEN;
+ c = rule.charAt(pos);
+ while (uprv_isRuleWhiteSpace(c) && pos < limit) {
+ ++pos;
+ c = rule.charAt(pos);
+ }
+
+ int32_t p = pos;
+
+ if (!parsingIDs) {
+ if (curData != NULL) {
+ if (direction == UTRANS_FORWARD)
+ dataVector.addElement(curData, status);
+ else
+ dataVector.insertElementAt(curData, 0, status);
+ curData = NULL;
+ }
+ parsingIDs = TRUE;
+ }
+
+ TransliteratorIDParser::SingleID* id =
+ TransliteratorIDParser::parseSingleID(rule, p, direction, status);
+ if (p != pos && ICU_Utility::parseChar(rule, p, END_OF_RULE)) {
+ // Successful ::ID parse.
+
+ if (direction == UTRANS_FORWARD) {
+ idBlockResult.append(id->canonID).append(END_OF_RULE);
+ } else {
+ idBlockResult.insert(0, END_OF_RULE);
+ idBlockResult.insert(0, id->canonID);
+ }
+
+ } else {
+ // Couldn't parse an ID. Try to parse a global filter
+ int32_t withParens = -1;
+ UnicodeSet* f = TransliteratorIDParser::parseGlobalFilter(rule, p, direction, withParens, NULL);
+ if (f != NULL) {
+ if (ICU_Utility::parseChar(rule, p, END_OF_RULE)
+ && (direction == UTRANS_FORWARD) == (withParens == 0))
+ {
+ if (compoundFilter != NULL) {
+ // Multiple compound filters
+ syntaxError(U_MULTIPLE_COMPOUND_FILTERS, rule, pos, status);
+ delete f;
+ } else {
+ compoundFilter = f;
+ compoundFilterOffset = ruleCount;
+ }
+ } else {
+ delete f;
+ }
+ } else {
+ // Invalid ::id
+ // Can be parsed as neither an ID nor a global filter
+ syntaxError(U_INVALID_ID, rule, pos, status);
+ }
+ }
+ delete id;
+ pos = p;
+ } else {
+ if (parsingIDs) {
+ 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 (!uprv_isRuleWhiteSpace(c2) && !u_iscntrl(c2) && !u_ispunct(c2)) {
+ /* It was escaped for a reason. Write what it was suppose to be. */
+ source+=5;
+ c = c2;
+ }
+ }
+ else if (c2 == QUOTE) {
+ /* \' seen. Make sure we don't do anything when we see it again. */
+ quoted = (UBool)!quoted;
+ }
+ }
+ }
+ if (c == CR || c == LF)
+ {
+ /* ignore spaces carriage returns, and all leading spaces on the next line.
+ * and line feed unless in the form \uXXXX
+ */
+ quoted = FALSE;
+ while (source < sourceLimit) {
+ c = *(source);
+ if (c != CR && c != LF && c != 0x0020) {
+ break;
+ }
+ source++;
+ }
+ continue;
+ }
+
+ /* Append UChar * after dissembling if c > 0xffff*/
+ index=0;
+ U16_APPEND_UNSAFE(target, index, c);
+ target+=index;
+ }
+ if (target < targetLimit) {
+ *target = 0;
+ }
+ return (int32_t)(target-targetStart);
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/rbt_pars.h b/Build/source/libs/icu/icu-4.6/i18n/rbt_pars.h
new file mode 100644
index 00000000000..96bdac06479
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_rule.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbt_rule.cpp
new file mode 100644
index 00000000000..69a22026374
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_rule.h b/Build/source/libs/icu/icu-4.6/i18n/rbt_rule.h
new file mode 100644
index 00000000000..0816956ce81
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_set.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbt_set.cpp
new file mode 100644
index 00000000000..1553c4f0419
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbt_set.h b/Build/source/libs/icu/icu-4.6/i18n/rbt_set.h
new file mode 100644
index 00000000000..f92e13002c2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/rbtz.cpp b/Build/source/libs/icu/icu-4.6/i18n/rbtz.cpp
new file mode 100644
index 00000000000..961c8fb2de4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regexcmp.cpp b/Build/source/libs/icu/icu-4.6/i18n/regexcmp.cpp
new file mode 100644
index 00000000000..bef729a9fb3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/regexcmp.cpp
@@ -0,0 +1,4323 @@
+//
+// file: regexcmp.cpp
+//
+// Copyright (C) 2002-2010 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 "util.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_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 (uprv_isRuleWhiteSpace(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.6/i18n/regexcmp.h b/Build/source/libs/icu/icu-4.6/i18n/regexcmp.h
new file mode 100644
index 00000000000..032fdb7f9cc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regexcst.h b/Build/source/libs/icu/icu-4.6/i18n/regexcst.h
new file mode 100644
index 00000000000..ab43137d8b6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regexcst.pl b/Build/source/libs/icu/icu-4.6/i18n/regexcst.pl
new file mode 100755
index 00000000000..f1dc06af7ec
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regexcst.txt b/Build/source/libs/icu/icu-4.6/i18n/regexcst.txt
new file mode 100644
index 00000000000..77ebd9606b4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regeximp.h b/Build/source/libs/icu/icu-4.6/i18n/regeximp.h
new file mode 100644
index 00000000000..3ee9102df1a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regexst.cpp b/Build/source/libs/icu/icu-4.6/i18n/regexst.cpp
new file mode 100644
index 00000000000..b8ad297d663
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regexst.h b/Build/source/libs/icu/icu-4.6/i18n/regexst.h
new file mode 100644
index 00000000000..07034d4450a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regextxt.cpp b/Build/source/libs/icu/icu-4.6/i18n/regextxt.cpp
new file mode 100644
index 00000000000..6960dac1b74
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/regextxt.h b/Build/source/libs/icu/icu-4.6/i18n/regextxt.h
new file mode 100644
index 00000000000..5b59838a92b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/reldtfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/reldtfmt.cpp
new file mode 100644
index 00000000000..c135c1d8782
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/reldtfmt.cpp
@@ -0,0 +1,472 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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);
+ }
+ }
+}
+
+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.6/i18n/reldtfmt.h b/Build/source/libs/icu/icu-4.6/i18n/reldtfmt.h
new file mode 100644
index 00000000000..692f9a95570
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/reldtfmt.h
@@ -0,0 +1,301 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef RELDTFMT_H
+#define RELDTFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse relative dates and times.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+
+U_NAMESPACE_BEGIN
+
+// forward declarations
+class MessageFormat;
+
+// internal structure used for caching strings
+struct URelativeString;
+
+/**
+ * This class is normally accessed using the kRelative or k...Relative values of EStyle as
+ * parameters to DateFormat::createDateInstance.
+ *
+ * Example:
+ * DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
+ *
+ * @draft ICU 3.8
+ */
+
+class RelativeDateFormat : public DateFormat {
+public:
+ RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const Locale& locale, UErrorCode& status);
+
+ // overrides
+ /**
+ * Copy constructor.
+ * @draft ICU 3.8
+ */
+ RelativeDateFormat(const RelativeDateFormat&);
+
+ /**
+ * Assignment operator.
+ * @draft ICU 3.8
+ */
+ RelativeDateFormat& operator=(const RelativeDateFormat&);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~RelativeDateFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const Format& other) const;
+
+
+ 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.
+ * @draft ICU 3.8
+ */
+ virtual UnicodeString& format( Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an object to produce a string. This method handles Formattable
+ * objects with a UDate type. If a the Formattable object type is not a Date,
+ * then it returns a failing UErrorCode.
+ *
+ * @param obj The object to format. Must be a Date.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.8
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+
+ /**
+ * Parse a date/time string beginning at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @param text The date/time string to be parsed
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @draft ICU 3.8
+ */
+ virtual void parse( const UnicodeString& text,
+ Calendar& cal,
+ ParsePosition& pos) const;
+
+ /**
+ * Parse a date/time string starting at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @see DateFormat::setLenient(boolean)
+ *
+ * @param text The date/time string to be parsed
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @draft ICU 3.8
+ */
+ UDate parse( const UnicodeString& text,
+ ParsePosition& pos) const;
+
+
+ /**
+ * Parse a date/time string. For example, a time text "07/10/96 4:5 PM, PDT"
+ * will be parsed into a UDate that is equivalent to Date(837039928046).
+ * Parsing begins at the beginning of the string and proceeds as far as
+ * possible. Assuming no parse errors were encountered, this function
+ * doesn't return any information about how much of the string was consumed
+ * by the parsing. If you need that information, use the version of
+ * parse() that takes a ParsePosition.
+ *
+ * @param text The date/time string to be parsed
+ * @param status Filled in with U_ZERO_ERROR if the parse was successful, and with
+ * an error value if there was a parse error.
+ * @return A valid UDate if the input could be parsed.
+ * @draft ICU 3.8
+ */
+ virtual UDate parse( const UnicodeString& text,
+ UErrorCode& status) const;
+
+ /**
+ * 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);
+
+
+private:
+ DateFormat *fDateFormat; // the held date format
+ DateFormat *fTimeFormat; // the held time format
+ MessageFormat *fCombinedFormat; // the {0} {1} format.
+
+ UDateFormatStyle fDateStyle;
+ UDateFormatStyle fTimeStyle;
+ Locale fLocale;
+
+ int32_t fDayMin; // day id of lowest #
+ int32_t fDayMax; // day id of highest #
+ int32_t fDatesLen; // Length of array
+ URelativeString *fDates; // array of strings
+
+
+ /**
+ * Get the string at a specific offset.
+ * @param day day offset ( -1, 0, 1, etc.. )
+ * @param len on output, length of string.
+ * @return the string, or NULL if none at that location.
+ */
+ const UChar *getStringForDay(int32_t day, int32_t &len, UErrorCode &status) const;
+
+ /**
+ * Load the Date string array
+ */
+ void loadDates(UErrorCode &status);
+
+ /**
+ * @return the number of days in "until-now"
+ */
+ static int32_t dayDifference(Calendar &until, UErrorCode &status);
+
+ /**
+ * initializes fCalendar from parameters. Returns fCalendar as a convenience.
+ * @param adoptZone Zone to be adopted, or NULL for TimeZone::createDefault().
+ * @param locale Locale of the calendar
+ * @param status Error code
+ * @return the newly constructed fCalendar
+ * @draft ICU 3.8
+ */
+ Calendar* initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status);
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // RELDTFMT_H
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/rematch.cpp b/Build/source/libs/icu/icu-4.6/i18n/rematch.cpp
new file mode 100644
index 00000000000..dda8a1ec3a2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/rematch.cpp
@@ -0,0 +1,6073 @@
+/*
+**************************************************************************
+* Copyright (C) 2002-2010 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) {
+ UTEXT_PREVIOUS32(replacement);
+ } else if (context.lastOffset != offset-1) {
+ utext_moveIndex32(replacement, offset - context.lastOffset - 1);
+ }
+ }
+ } else {
+ 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;
+ }
+ 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);
+ 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);
+ 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) {
+ 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;
+}
+
+
+
+
+
+//--------------------------------------------------------------------------------
+//
+// 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;
+ UBool lastGroupWasNullUText = FALSE;
+ for (groupNum=1; groupNum<=numCaptureGroups; groupNum++) {
+ if (i==destCapacity-1) {
+ break;
+ }
+ i++;
+ lastGroupWasNullUText = (dest[i] == NULL ? TRUE : FALSE);
+ dest[i] = group(groupNum, dest[i], status);
+ }
+
+ if (nextOutputStringStart == fActiveLimit) {
+ // The delimiter was at the end of the string. We're done.
+ break;
+ } else if (i == destCapacity-1) {
+ // We're out of capture groups, and the rest of the string is more important
+ if (lastGroupWasNullUText) {
+ utext_close(dest[i]);
+ dest[i] = NULL;
+ }
+ }
+
+ }
+ 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 && (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;
+ 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;
+ 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;
+ 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;
+ }
+ 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) {
+ 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);
+ 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);
+ 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.6/i18n/remtrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/remtrans.cpp
new file mode 100644
index 00000000000..c21c79b4f94
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/remtrans.h b/Build/source/libs/icu/icu-4.6/i18n/remtrans.h
new file mode 100644
index 00000000000..25a5609dffe
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/repattrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/repattrn.cpp
new file mode 100644
index 00000000000..4369eb83f76
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/repattrn.cpp
@@ -0,0 +1,839 @@
+//
+// file: repattrn.cpp
+//
+/*
+***************************************************************************
+* Copyright (C) 2002-2010 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, UText mode
+//
+RegexMatcher *RegexPattern::matcher(UText *input,
+ PatternIsUTextFlag /*flag*/,
+ UErrorCode &status) const {
+ RegexMatcher *retMatcher = matcher(status);
+ if (retMatcher != NULL) {
+ retMatcher->fDeferredStatus = status;
+ retMatcher->reset(input);
+ }
+ return retMatcher;
+}
+
+#if 0
+RegexMatcher *RegexPattern::matcher(const UChar * /*input*/,
+ UErrorCode &status) const
+{
+ /* This should never get called. The API with UnicodeString should be called instead. */
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return NULL;
+}
+#endif
+
+//---------------------------------------------------------------------
+//
+// matcher(status)
+//
+//---------------------------------------------------------------------
+RegexMatcher *RegexPattern::matcher(UErrorCode &status) const {
+ RegexMatcher *retMatcher = NULL;
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return NULL;
+ }
+
+ retMatcher = new RegexMatcher(this);
+ if (retMatcher == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return retMatcher;
+}
+
+
+
+//---------------------------------------------------------------------
+//
+// matches Convenience function to test for a match, starting
+// with a pattern string and a data string.
+//
+//---------------------------------------------------------------------
+UBool U_EXPORT2 RegexPattern::matches(const UnicodeString &regex,
+ const UnicodeString &input,
+ UParseError &pe,
+ UErrorCode &status) {
+
+ if (U_FAILURE(status)) {return FALSE;}
+
+ UBool retVal;
+ RegexPattern *pat = NULL;
+ RegexMatcher *matcher = NULL;
+
+ pat = RegexPattern::compile(regex, 0, pe, status);
+ matcher = pat->matcher(input, status);
+ retVal = matcher->matches(status);
+
+ delete matcher;
+ delete pat;
+ return retVal;
+}
+
+
+//
+// matches, UText mode
+//
+UBool U_EXPORT2 RegexPattern::matches(UText *regex,
+ UText *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, PATTERN_IS_UTEXT, status);
+ 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.6/i18n/search.cpp b/Build/source/libs/icu/icu-4.6/i18n/search.cpp
new file mode 100644
index 00000000000..5d2aa139415
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/selfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/selfmt.cpp
new file mode 100644
index 00000000000..090b6439dce
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/selfmt.cpp
@@ -0,0 +1,447 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2010, 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/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/uchar.h"
+#include "unicode/umsg.h"
+#include "unicode/rbnf.h"
+#include "cmemory.h"
+#include "util.h"
+#include "uassert.h"
+#include "ustrfmt.h"
+#include "uvector.h"
+
+#include "unicode/selfmt.h"
+#include "selfmtimpl.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat)
+
+#define MAX_KEYWORD_SIZE 30
+static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0};
+
+SelectFormat::SelectFormat(const UnicodeString& pat, UErrorCode& status) : parsedValuesHash(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ initHashTable(status);
+ applyPattern(pat, status);
+}
+
+SelectFormat::SelectFormat(const SelectFormat& other) : Format(other), parsedValuesHash(NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ pattern = other.pattern;
+ copyHashtable(other.parsedValuesHash, status);
+}
+
+SelectFormat::~SelectFormat() {
+ cleanHashTable();
+}
+
+void SelectFormat::initHashTable(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // has inited
+ if (parsedValuesHash != NULL) {
+ return;
+ }
+
+ parsedValuesHash = new Hashtable(TRUE, status);
+ if (U_FAILURE(status)) {
+ cleanHashTable();
+ return;
+ } else {
+ if (parsedValuesHash == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ // to use hashtable->equals(), must set Value Compartor.
+ parsedValuesHash->setValueComparator(uhash_compareCaselessUnicodeString);
+}
+
+void SelectFormat::cleanHashTable() {
+ if (parsedValuesHash != NULL) {
+ delete parsedValuesHash;
+ parsedValuesHash = NULL;
+ }
+}
+
+void
+SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ pattern = newPattern;
+ enum State{ startState, keywordState, pastKeywordState, phraseState};
+
+ //Initialization
+ UnicodeString keyword ;
+ UnicodeString phrase ;
+ UnicodeString* ptrPhrase ;
+ int32_t braceCount = 0;
+
+ if (parsedValuesHash == NULL) {
+ initHashTable(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ parsedValuesHash->removeAll();
+ parsedValuesHash->setValueDeleter(uhash_deleteUnicodeString);
+
+ //Process the state machine
+ State state = startState;
+ for (int32_t i = 0; i < pattern.length(); ++i) {
+ //Get the character and check its type
+ UChar ch = pattern.charAt(i);
+ CharacterClass type = classifyCharacter(ch);
+
+ //Allow any character in phrase but nowhere else
+ if ( type == tOther ) {
+ if ( state == phraseState ){
+ phrase += ch;
+ continue;
+ }else {
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }
+ }
+
+ //Process the state machine
+ switch (state) {
+ //At the start of pattern
+ case startState:
+ switch (type) {
+ case tSpace:
+ break;
+ case tStartKeyword:
+ state = keywordState;
+ keyword += ch;
+ break;
+ //If anything else is encountered, it's a syntax error
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }//end of switch(type)
+ break;
+
+ //Handle the keyword state
+ case keywordState:
+ switch (type) {
+ case tSpace:
+ state = pastKeywordState;
+ break;
+ case tStartKeyword:
+ case tContinueKeyword:
+ keyword += ch;
+ break;
+ case tLeftBrace:
+ state = phraseState;
+ break;
+ //If anything else is encountered, it's a syntax error
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }//end of switch(type)
+ break;
+
+ //Handle the pastkeyword state
+ case pastKeywordState:
+ switch (type) {
+ case tSpace:
+ break;
+ case tLeftBrace:
+ state = phraseState;
+ break;
+ //If anything else is encountered, it's a syntax error
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }//end of switch(type)
+ break;
+
+ //Handle the phrase state
+ case phraseState:
+ switch (type) {
+ case tLeftBrace:
+ braceCount++;
+ phrase += ch;
+ break;
+ case tRightBrace:
+ //Matching keyword, phrase pair found
+ if (braceCount == 0){
+ //Check validity of keyword
+ if (parsedValuesHash->get(keyword) != NULL) {
+ status = U_DUPLICATE_KEYWORD;
+ cleanHashTable();
+ return;
+ }
+ if (keyword.length() == 0) {
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }
+
+ //Store the keyword, phrase pair in hashTable
+ ptrPhrase = new UnicodeString(phrase);
+ parsedValuesHash->put( keyword, ptrPhrase, status);
+
+ //Reinitialize
+ keyword.remove();
+ phrase.remove();
+ ptrPhrase = NULL;
+ state = startState;
+ }
+
+ if (braceCount > 0){
+ braceCount-- ;
+ phrase += ch;
+ }
+ break;
+ default:
+ phrase += ch;
+ }//end of switch(type)
+ break;
+
+ //Handle the default case of switch(state)
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+
+ }//end of switch(state)
+ }
+
+ //Check if the state machine is back to startState
+ if ( state != startState){
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }
+
+ //Check if "other" keyword is present
+ if ( !checkSufficientDefinition() ) {
+ status = U_DEFAULT_KEYWORD_MISSING;
+ cleanHashTable();
+ }
+ return;
+}
+
+UnicodeString&
+SelectFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ switch (obj.getType())
+ {
+ case Formattable::kString:
+ return format(obj.getString(), appendTo, pos, status);
+ default:
+ if( U_SUCCESS(status) ){
+ 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;
+
+ if (parsedValuesHash == NULL) {
+ status = U_INVALID_FORMAT_ERROR;
+ return appendTo;
+ }
+
+ //Check for the validity of the keyword
+ if ( !checkValidKeyword(keyword) ){
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ UnicodeString *selectedPattern = (UnicodeString *)parsedValuesHash->get(keyword);
+ if (selectedPattern == NULL) {
+ selectedPattern = (UnicodeString *)parsedValuesHash->get(SELECT_KEYWORD_OTHER);
+ }
+
+ return appendTo += *selectedPattern;
+}
+
+UnicodeString&
+SelectFormat::toPattern(UnicodeString& appendTo) {
+ return appendTo += pattern;
+}
+
+SelectFormat::CharacterClass
+SelectFormat::classifyCharacter(UChar ch) const{
+ if ((ch >= CAP_A) && (ch <= CAP_Z)) {
+ return tStartKeyword;
+ }
+ if ((ch >= LOW_A) && (ch <= LOW_Z)) {
+ return tStartKeyword;
+ }
+ if ((ch >= U_ZERO) && (ch <= U_NINE)) {
+ return tContinueKeyword;
+ }
+ if ( uprv_isRuleWhiteSpace(ch) ){
+ return tSpace;
+ }
+ switch (ch) {
+ case LEFTBRACE:
+ return tLeftBrace;
+ case RIGHTBRACE:
+ return tRightBrace;
+ case HYPHEN:
+ case LOWLINE:
+ return tContinueKeyword;
+ default :
+ return tOther;
+ }
+}
+
+UBool
+SelectFormat::checkSufficientDefinition() {
+ // Check that at least the default rule is defined.
+ return (parsedValuesHash != NULL &&
+ parsedValuesHash->get(SELECT_KEYWORD_OTHER) != NULL) ;
+}
+
+UBool
+SelectFormat::checkValidKeyword(const UnicodeString& argKeyword ) const{
+ int32_t len = argKeyword.length();
+ if (len < 1){
+ return FALSE;
+ }
+ CharacterClass type = classifyCharacter(argKeyword.charAt(0));
+ if( type != tStartKeyword ){
+ return FALSE;
+ }
+
+ for (int32_t i = 0; i < argKeyword.length(); ++i) {
+ type = classifyCharacter(argKeyword.charAt(i));
+ if( type != tStartKeyword && type != tContinueKeyword ){
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+Format* SelectFormat::clone() const
+{
+ return new SelectFormat(*this);
+}
+
+SelectFormat&
+SelectFormat::operator=(const SelectFormat& other) {
+ if (this != &other) {
+ UErrorCode status = U_ZERO_ERROR;
+ pattern = other.pattern;
+ copyHashtable(other.parsedValuesHash, status);
+ }
+ return *this;
+}
+
+UBool
+SelectFormat::operator==(const Format& other) const {
+ if( this == &other){
+ return TRUE;
+ }
+ if (typeid(*this) != typeid(other)) {
+ return FALSE;
+ }
+ SelectFormat* fmt = (SelectFormat*)&other;
+ Hashtable* hashOther = fmt->parsedValuesHash;
+ if ( parsedValuesHash == NULL && hashOther == NULL)
+ return TRUE;
+ if ( parsedValuesHash == NULL || hashOther == NULL)
+ return FALSE;
+ return parsedValuesHash->equals(*hashOther);
+}
+
+UBool
+SelectFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+void
+SelectFormat::parseObject(const UnicodeString& /*source*/,
+ Formattable& /*result*/,
+ ParsePosition& pos) const
+{
+ // TODO: not yet supported in icu4j and icu4c
+ pos.setErrorIndex(pos.getIndex());
+}
+
+void
+SelectFormat::copyHashtable(Hashtable *other, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (other == NULL) {
+ cleanHashTable();
+ return;
+ }
+ if (parsedValuesHash == NULL) {
+ initHashTable(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ parsedValuesHash->removeAll();
+ parsedValuesHash->setValueDeleter(uhash_deleteUnicodeString);
+
+ 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;
+ const UHashTok otherKeyToVal = elem->value;
+ UnicodeString* otherValue = (UnicodeString*)otherKeyToVal.pointer;
+ parsedValuesHash->put(*otherKey, new UnicodeString(*otherValue), status);
+ if (U_FAILURE(status)){
+ cleanHashTable();
+ return;
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/selfmtimpl.h b/Build/source/libs/icu/icu-4.6/i18n/selfmtimpl.h
new file mode 100644
index 00000000000..208a6599a2e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/selfmtimpl.h
@@ -0,0 +1,97 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Copyright (C) 2010 , Yahoo! Inc.
+ ********************************************************************
+ * File SELECTFMT_IMPL.H
+ *
+ * Date Name Description
+ * 11/11/09 kirtig Finished first cut of implementation.
+ *********************************************************************/
+
+
+#ifndef SELFMTIMPL
+#define SELFMTIMPL
+
+/**
+ * \file
+ * \brief C++ API: Defines rules for mapping positive long values onto a small set of keywords.
+ */
+
+#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.6/i18n/simpletz.cpp b/Build/source/libs/icu/icu-4.6/i18n/simpletz.cpp
new file mode 100644
index 00000000000..fb960bbf01a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/smpdtfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/smpdtfmt.cpp
new file mode 100644
index 00000000000..86e98cba0be
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/smpdtfmt.cpp
@@ -0,0 +1,3295 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File SMPDTFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/31/97 aliu Modified extensively to work with 50 locales.
+* 04/01/97 aliu Added support for centuries.
+* 07/09/97 helena Made ParsePosition into a class.
+* 07/21/98 stephen Added initializeDefaultCentury.
+* Removed getZoneIndex (added in DateFormatSymbols)
+* Removed subParseLong
+* Removed chk
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+* 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru
+* "99" are recognized. {j28 4182066}
+* 11/15/99 weiv Added support for week of year/day of week format
+********************************************************************************
+*/
+
+#define ZID_KEY_MAX 128
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/ures.h"
+#include "unicode/msgfmt.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/timezone.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/basictz.h"
+#include "unicode/simpletz.h"
+#include "unicode/rbtz.h"
+#include "unicode/vtzone.h"
+#include "olsontz.h"
+#include "util.h"
+#include "fphdlimp.h"
+#include "gregoimp.h"
+#include "hebrwcal.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "zstrfmt.h"
+#include "cmemory.h"
+#include "umutex.h"
+#include <float.h>
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+#include <stdio.h>
+#endif
+
+// *****************************************************************************
+// class SimpleDateFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+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
+
+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);
+ }
+
+ while (fOverrideList) {
+ NSOverride *cur = fOverrideList;
+ fOverrideList = cur->next;
+ delete cur->nf;
+ uprv_free(cur);
+ }
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
+ : fLocale(Locale::getDefault()),
+ fSymbols(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),
+ 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),
+ 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),
+ 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),
+ 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),
+ 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)),
+ 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),
+ 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),
+ 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),
+ 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;
+
+ 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"
+
+ 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 (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 += gGmtMinus;
+ offset = -offset; // suppress the '-' sign for text display.
+ }else{
+ appendTo += gGmtPlus;
+ }
+
+ offset /= U_MILLIS_PER_SECOND; // now in seconds
+ int32_t sec = offset % 60;
+ offset /= 60;
+ int32_t min = offset % 60;
+ int32_t hour = offset / 60;
+
+
+ zeroPaddingNumber(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);
+ 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 ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
+ if (zsf) {
+ if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
+ if (count < 4) {
+ // "z", "zz", "zzz"
+ zsf->getSpecificShortString(cal, TRUE /*commonly used only*/,
+ zoneString, status);
+ } else {
+ // "zzzz"
+ zsf->getSpecificLongString(cal, zoneString, status);
+ }
+ } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
+ if (count == 1) {
+ // "v"
+ zsf->getGenericShortString(cal, TRUE /*commonly used only*/,
+ zoneString, status);
+ } else if (count == 4) {
+ // "vvvv"
+ zsf->getGenericLongString(cal, zoneString, status);
+ }
+ } else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
+ if (count == 1) {
+ // "V"
+ zsf->getSpecificShortString(cal, FALSE /*ignore commonly used*/,
+ zoneString, status);
+ } else if (count == 4) {
+ // "VVVV"
+ zsf->getGenericLocationString(cal, zoneString, status);
+ }
+ }
+ }
+ if (zoneString.isEmpty()) {
+ appendGMT(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;
+
+ // 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 (uprv_isRuleWhiteSpace(ch)) {
+ i++;
+ // Advance over run in pattern
+ while ((i+1)<fPattern.length() &&
+ uprv_isRuleWhiteSpace(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
+
+ // Handle quotes. Two consecutive quotes is a quote
+ // literal, inside or outside of quotes. Otherwise a
+ // quote indicates entry or exit from a quoted region.
+ if (ch == QUOTE) {
+ // Match a quote literal '' within OR outside of quotes
+ if ((i+1)<fPattern.length() && fPattern.charAt(i+1)==ch) {
+ ++i; // Skip over doubled quote
+ // Fall through and treat quote as a literal
+ } else {
+ // Enter or exit quoted region
+ inQuote = !inQuote;
+ continue;
+ }
+ }
+
+ // A run of white space in the pattern matches a run
+ // of white space in the input text.
+ if (uprv_isRuleWhiteSpace(ch)) {
+ // Advance over run in pattern
+ while ((i+1)<fPattern.length() &&
+ uprv_isRuleWhiteSpace(fPattern.charAt(i+1))) {
+ ++i;
+ }
+
+ // Advance over run in input text
+ int32_t s = pos;
+ while (pos<text.length() &&
+ ( u_isUWhiteSpace(text.charAt(pos)) || uprv_isRuleWhiteSpace(text.charAt(pos)))) {
+ ++pos;
+ }
+
+ // Must see at least one white space char in input
+ if (pos > s) {
+ continue;
+ }
+
+
+ } else if (pos<text.length() && text.charAt(pos)==ch) {
+ // Match a literal
+ ++pos;
+ continue;
+ }
+
+ // We fall through to this point if the match fails
+ 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;
+}
+
+//----------------------------------------------------------------------
+
+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);
+
+#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) || !uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ start += UTF_CHAR_LENGTH(c);
+ }
+ pos.setIndex(start);
+
+ // We handle a few special cases here where we need to parse
+ // a number value. We handle further, more generic cases below. We need
+ // to handle some of them here because some fields require extra processing on
+ // the parsed value.
+ if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||
+ patternCharIndex == UDAT_HOUR1_FIELD ||
+ (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) ||
+ patternCharIndex == UDAT_YEAR_FIELD ||
+ patternCharIndex == UDAT_YEAR_WOY_FIELD ||
+ patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)
+ {
+ int32_t parseStart = pos.getIndex();
+ // It would be good to unify this with the obeyCount logic below,
+ // but that's going to be difficult.
+ const UnicodeString* src;
+
+ if (obeyCount) {
+ if ((start+count) > text.length()) {
+ return -start;
+ }
+
+ text.extractBetween(0, start + count, temp);
+ src = &temp;
+ } else {
+ src = &text;
+ }
+
+ parseInt(*src, number, pos, allowNegative,currentNumberFormat);
+
+ if (pos.getIndex() == parseStart)
+ return -start;
+ value = number.getLong();
+
+ // suffix processing
+ int32_t txtLoc = pos.getIndex();
+ if (value <0 ) {
+ txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
+ if (txtLoc != pos.getIndex()) {
+ value *= -1;
+ }
+ }
+ else {
+ txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
+ }
+ pos.setIndex(txtLoc);
+
+ }
+
+ switch (patternCharIndex) {
+ case UDAT_ERA_FIELD:
+ if (count == 5) {
+ ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal);
+ }
+ 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 (count <= 2 && (pos.getIndex() - start) == 2
+ && u_isdigit(text.charAt(start))
+ && u_isdigit(text.charAt(start+1)))
+ {
+ // Assume for example that the defaultCenturyStart is 6/18/1903.
+ // This means that two-digit years will be forced into the range
+ // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02
+ // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond
+ // to 1904, 1905, etc. If the year is 03, then it is 2003 if the
+ // other fields specify a date before 6/18, or 1903 if they specify a
+ // date afterwards. As a result, 03 is an ambiguous year. All other
+ // two-digit years are unambiguous.
+ if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
+ int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
+ ambiguousYear[0] = (value == ambiguousTwoDigitYear);
+ value += (fDefaultCenturyStartYear/100)*100 +
+ (value < ambiguousTwoDigitYear ? 100 : 0);
+ }
+ }
+ cal.set(UCAL_YEAR, value);
+
+ // 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 (count <= 2 && (pos.getIndex() - start) == 2
+ && u_isdigit(text.charAt(start))
+ && u_isdigit(text.charAt(start+1))
+ && fHaveDefaultCentury )
+ {
+ int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
+ ambiguousYear[0] = (value == ambiguousTwoDigitYear);
+ value += (fDefaultCenturyStartYear/100)*100 +
+ (value < ambiguousTwoDigitYear ? 100 : 0);
+ }
+ cal.set(UCAL_YEAR_WOY, value);
+ return pos.getIndex();
+
+ case UDAT_MONTH_FIELD:
+ if (count <= 2) // i.e., M or MM.
+ {
+ // 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 (count <= 2) // i.e., L or LL.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: M or MM.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, value - 1);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., LLL or LLLL
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, cal);
+ }
+
+ case UDAT_HOUR_OF_DAY1_FIELD:
+ // [We computed 'value' above.]
+ if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
+ value = 0;
+ cal.set(UCAL_HOUR_OF_DAY, value);
+ return pos.getIndex();
+
+ case UDAT_FRACTIONAL_SECOND_FIELD:
+ // Fractional seconds left-justify
+ i = pos.getIndex() - start;
+ if (i < 3) {
+ while (i < 3) {
+ value *= 10;
+ i++;
+ }
+ } else {
+ int32_t a = 1;
+ while (i > 3) {
+ a *= 10;
+ i--;
+ }
+ value = (value + (a>>1)) / a;
+ }
+ cal.set(UCAL_MILLISECOND, value);
+ return pos.getIndex();
+
+ case UDAT_DOW_LOCAL_FIELD:
+ if (count <= 2) // 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 (count <= 2) // 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;
+ cal.set(UCAL_HOUR, value);
+ return pos.getIndex();
+
+ case UDAT_QUARTER_FIELD:
+ if (count <= 2) // i.e., Q or QQ.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: Q or QQ.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, (value - 1) * 3);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., QQQ or QQQQ
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal);
+ }
+
+ case UDAT_STANDALONE_QUARTER_FIELD:
+ if (count <= 2) // i.e., q or qq.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: q or q.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, (value - 1) * 3);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., qqq or qqqq
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal);
+ }
+
+ case UDAT_TIMEZONE_FIELD:
+ case UDAT_TIMEZONE_RFC_FIELD:
+ case UDAT_TIMEZONE_GENERIC_FIELD:
+ case UDAT_TIMEZONE_SPECIAL_FIELD:
+ {
+ int32_t offset = 0;
+ UBool parsed = FALSE;
+
+ // Step 1
+ // Check if this is a long GMT offset string (either localized or default)
+ offset = parseGMT(text, pos);
+ if (pos.getIndex() - start > 0) {
+ parsed = TRUE;
+ }
+ if (!parsed) {
+ // Step 2
+ // Check if this is an RFC822 time zone offset.
+ // ICU supports the standard RFC822 format [+|-]HHmm
+ // and its extended form [+|-]HHmmSS.
+ do {
+ int32_t sign = 0;
+ UChar signChar = text.charAt(start);
+ if (signChar == (UChar)0x002B /* '+' */) {
+ sign = 1;
+ } else if (signChar == (UChar)0x002D /* '-' */) {
+ sign = -1;
+ } else {
+ // Not an RFC822 offset string
+ break;
+ }
+
+ // Parse digits
+ int32_t orgPos = start + 1;
+ pos.setIndex(orgPos);
+ parseInt(text, number, 6, pos, FALSE,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
+ // At this point, check for named time zones by looking through
+ // the locale data from the DateFormatZoneData strings.
+ // Want to be able to parse both short and long forms.
+ // optimize for calendar's current time zone
+ const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
+ if (zsf) {
+ UErrorCode status = U_ZERO_ERROR;
+ const ZoneStringInfo *zsinfo = NULL;
+ int32_t matchLen;
+
+ switch (patternCharIndex) {
+ case UDAT_TIMEZONE_FIELD: // 'z'
+ if (count < 4) {
+ zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
+ } else {
+ zsinfo = zsf->findSpecificLong(text, start, matchLen, status);
+ }
+ break;
+ case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
+ if (count == 1) {
+ zsinfo = zsf->findGenericShort(text, start, matchLen, status);
+ } else if (count == 4) {
+ zsinfo = zsf->findGenericLong(text, start, matchLen, status);
+ }
+ break;
+ case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
+ if (count == 1) {
+ zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
+ } else if (count == 4) {
+ zsinfo = zsf->findGenericLocation(text, start, matchLen, status);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (U_SUCCESS(status) && zsinfo != NULL) {
+ if (zsinfo->isStandard()) {
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
+ } else if (zsinfo->isDaylight()) {
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
+ }
+ UnicodeString tzid;
+ zsinfo->getID(tzid);
+
+ UnicodeString current;
+ cal.getTimeZone().getID(current);
+ if (tzid != current) {
+ TimeZone *tz = TimeZone::createTimeZone(tzid);
+ cal.adoptTimeZone(tz);
+ }
+ return start + matchLen;
+ }
+ }
+ // Step 4
+ // Final attempt - is this standalone GMT/UT/UTC?
+ int32_t gmtLen = 0;
+ 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 (gmtLen > 0) {
+ TimeZone *tz = TimeZone::createTimeZone(UnicodeString("Etc/GMT"));
+ 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) {
+ cal.set(field, number.getLong());
+ return pos.getIndex();
+ }
+ return -start;
+ }
+}
+
+/**
+ * Parse an integer using fNumberFormat. This method is semantically
+ * const, but actually may modify fNumberFormat.
+ */
+void SimpleDateFormat::parseInt(const UnicodeString& text,
+ Formattable& number,
+ ParsePosition& pos,
+ UBool allowNegative,
+ 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(SUPPRESS_NEGATIVE_PREFIX);
+ }
+ 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, DateFormatSymbols::getPatternUChars(), fSymbols->fLocalPatternChars, status);
+ return result;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::applyPattern(const UnicodeString& pattern)
+{
+ fPattern = pattern;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
+ UErrorCode &status)
+{
+ translatePattern(pattern, fPattern, fSymbols->fLocalPatternChars, DateFormatSymbols::getPatternUChars(), status);
+}
+
+//----------------------------------------------------------------------
+
+const DateFormatSymbols*
+SimpleDateFormat::getDateFormatSymbols() const
+{
+ return fSymbols;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
+{
+ delete fSymbols;
+ fSymbols = newFormatSymbols;
+}
+
+//----------------------------------------------------------------------
+void
+SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
+{
+ delete fSymbols;
+ fSymbols = new DateFormatSymbols(newFormatSymbols);
+}
+
+
+//----------------------------------------------------------------------
+
+
+void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormat::adoptCalendar(calendarToAdopt);
+ delete fSymbols;
+ fSymbols=NULL;
+ initializeSymbols(fLocale, fCalendar, status); // we need new symbols
+ initializeDefaultCentury(); // we need a new century (possibly)
+}
+
+
+//----------------------------------------------------------------------
+
+
+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 (uprv_isRuleWhiteSpace(c)) {
+ // We may have a pattern like: \u200F \u0020
+ // and input text like: \u200F \u0020
+ // Note that U+200F and U+0020 are RuleWhiteSpace but only
+ // U+0020 is UWhiteSpace. So we have to first do a direct
+ // match of the run of RULE whitespace in the pattern,
+ // then match any extra characters.
+ UBool literalMatch = FALSE;
+ while (pos < input.length() &&
+ input.char32At(pos) == c) {
+ literalMatch = TRUE;
+ i += len;
+ pos += len;
+ if (i == affix.length()) {
+ break;
+ }
+ c = affix.char32At(i);
+ len = U16_LENGTH(c);
+ if (!uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ }
+
+ // Advance over run in pattern
+ i = skipRuleWhiteSpace(affix, i);
+
+ // Advance over run in input text
+ // Must see at least one white space char in input,
+ // unless we've already matched some characters literally.
+ int32_t s = pos;
+ pos = skipUWhiteSpace(input, pos);
+ if (pos == s && !literalMatch) {
+ return -1;
+ }
+
+ // 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::skipRuleWhiteSpace(const UnicodeString& text, int32_t pos) const {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+//----------------------------------------------------------------------
+
+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;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/sortkey.cpp b/Build/source/libs/icu/icu-4.6/i18n/sortkey.cpp
new file mode 100644
index 00000000000..ceca9d16506
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/sortkey.cpp
@@ -0,0 +1,403 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+//===============================================================================
+//
+// File sortkey.cpp
+//
+//
+//
+// Created by: Helena Shih
+//
+// Modification History:
+//
+// Date Name Description
+//
+// 6/20/97 helena Java class name change.
+// 6/23/97 helena Added comments to make code more readable.
+// 6/26/98 erm Canged to use byte arrays instead of UnicodeString
+// 7/31/98 erm hashCode: minimum inc should be 2 not 1,
+// Cleaned up operator=
+// 07/12/99 helena HPUX 11 CC port.
+// 03/06/01 synwee Modified compareTo, to handle the result of
+// 2 string similar in contents, but one is longer
+// than the other
+//===============================================================================
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/sortkey.h"
+#include "cmemory.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+// A hash code of kInvalidHashCode indicates that the has code needs
+// to be computed. A hash code of kEmptyHashCode is used for empty keys
+// and for any key whose computed hash code is kInvalidHashCode.
+#define kInvalidHashCode ((int32_t)0)
+#define kEmptyHashCode ((int32_t)1)
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationKey)
+
+CollationKey::CollationKey()
+ : UObject(), fBogus(FALSE), fCount(0), fCapacity(0),
+ fHashCode(kEmptyHashCode), fBytes(NULL)
+{
+}
+
+// Create a collation key from a bit array.
+CollationKey::CollationKey(const uint8_t* newValues, int32_t count)
+ : UObject(), fBogus(FALSE), fCount(count), fCapacity(count),
+ fHashCode(kInvalidHashCode)
+{
+ fBytes = (uint8_t *)uprv_malloc(count);
+
+ if (fBytes == NULL)
+ {
+ setToBogus();
+ return;
+ }
+
+ uprv_memcpy(fBytes, newValues, fCount);
+}
+
+CollationKey::CollationKey(const CollationKey& other)
+: UObject(other), fBogus(FALSE), fCount(other.fCount), fCapacity(other.fCapacity),
+ fHashCode(other.fHashCode), fBytes(NULL)
+{
+ if (other.fBogus)
+ {
+ setToBogus();
+ return;
+ }
+
+ fBytes = (uint8_t *)uprv_malloc(fCapacity);
+
+ if (fBytes == NULL)
+ {
+ setToBogus();
+ return;
+ }
+
+ uprv_memcpy(fBytes, other.fBytes, other.fCount);
+ if(fCapacity>fCount) {
+ uprv_memset(fBytes+fCount, 0, fCapacity-fCount);
+ }
+}
+
+CollationKey::~CollationKey()
+{
+ uprv_free(fBytes);
+}
+
+void CollationKey::adopt(uint8_t *values, int32_t count) {
+ if(fBytes != NULL) {
+ uprv_free(fBytes);
+ }
+ fBogus = FALSE;
+ fBytes = values;
+ fCount = count;
+ fCapacity = count;
+ fHashCode = kInvalidHashCode;
+}
+
+// set the key to an empty state
+CollationKey&
+CollationKey::reset()
+{
+ fCount = 0;
+ fBogus = FALSE;
+ fHashCode = kEmptyHashCode;
+
+ return *this;
+}
+
+// set the key to a "bogus" or invalid state
+CollationKey&
+CollationKey::setToBogus()
+{
+ uprv_free(fBytes);
+ fBytes = NULL;
+
+ fCapacity = 0;
+ fCount = 0;
+ fHashCode = kInvalidHashCode;
+
+ return *this;
+}
+
+UBool
+CollationKey::operator==(const CollationKey& source) const
+{
+ return (this->fCount == source.fCount &&
+ (this->fBytes == source.fBytes ||
+ uprv_memcmp(this->fBytes, source.fBytes, this->fCount) == 0));
+}
+
+const CollationKey&
+CollationKey::operator=(const CollationKey& other)
+{
+ if (this != &other)
+ {
+ if (other.isBogus())
+ {
+ return setToBogus();
+ }
+
+ if (other.fBytes != NULL)
+ {
+ ensureCapacity(other.fCount);
+
+ if (isBogus())
+ {
+ return *this;
+ }
+
+ fHashCode = other.fHashCode;
+ uprv_memcpy(fBytes, other.fBytes, fCount);
+ }
+ else
+ {
+ fCount = 0;
+ fBogus = FALSE;
+ fHashCode = kEmptyHashCode;
+ }
+ }
+
+ return *this;
+}
+
+// Bitwise comparison for the collation keys.
+// NOTE: this is somewhat messy 'cause we can't count
+// on memcmp returning the exact values which match
+// Collator::EComparisonResult
+Collator::EComparisonResult
+CollationKey::compareTo(const CollationKey& target) const
+{
+ uint8_t *src = this->fBytes;
+ uint8_t *tgt = target.fBytes;
+
+ // are we comparing the same string
+ if (src == tgt)
+ return Collator::EQUAL;
+
+ /*
+ int count = (this->fCount < target.fCount) ? this->fCount : target.fCount;
+ if (count == 0)
+ {
+ // If count is 0, at least one of the keys is empty.
+ // An empty key is always LESS than a non-empty one
+ // and EQUAL to another empty
+ if (this->fCount < target.fCount)
+ {
+ return Collator::LESS;
+ }
+
+ if (this->fCount > target.fCount)
+ {
+ return Collator::GREATER;
+ }
+ return Collator::EQUAL;
+ }
+ */
+
+ int minLength;
+ Collator::EComparisonResult result;
+
+ // are we comparing different lengths?
+ if (this->fCount != target.fCount) {
+ if (this->fCount < target.fCount) {
+ minLength = this->fCount;
+ result = Collator::LESS;
+ }
+ else {
+ minLength = target.fCount;
+ result = Collator::GREATER;
+ }
+ }
+ else {
+ minLength = target.fCount;
+ result = Collator::EQUAL;
+ }
+
+ if (minLength > 0) {
+ int diff = uprv_memcmp(src, tgt, minLength);
+ if (diff > 0) {
+ return Collator::GREATER;
+ }
+ else
+ if (diff < 0) {
+ return Collator::LESS;
+ }
+ }
+
+ return result;
+ /*
+ if (result < 0)
+ {
+ return Collator::LESS;
+ }
+
+ if (result > 0)
+ {
+ return Collator::GREATER;
+ }
+ return Collator::EQUAL;
+ */
+}
+
+// Bitwise comparison for the collation keys.
+UCollationResult
+CollationKey::compareTo(const CollationKey& target, UErrorCode &status) const
+{
+ if(U_SUCCESS(status)) {
+ uint8_t *src = this->fBytes;
+ uint8_t *tgt = target.fBytes;
+
+ // are we comparing the same string
+ if (src == tgt)
+ return UCOL_EQUAL;
+
+ int minLength;
+ UCollationResult result;
+
+ // are we comparing different lengths?
+ if (this->fCount != target.fCount) {
+ if (this->fCount < target.fCount) {
+ minLength = this->fCount;
+ result = UCOL_LESS;
+ }
+ else {
+ minLength = target.fCount;
+ result = UCOL_GREATER;
+ }
+ }
+ else {
+ minLength = target.fCount;
+ result = UCOL_EQUAL;
+ }
+
+ if (minLength > 0) {
+ int diff = uprv_memcmp(src, tgt, minLength);
+ if (diff > 0) {
+ return UCOL_GREATER;
+ }
+ else
+ if (diff < 0) {
+ return UCOL_LESS;
+ }
+ }
+
+ return result;
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+CollationKey&
+CollationKey::ensureCapacity(int32_t newSize)
+{
+ if (fCapacity < newSize)
+ {
+ uprv_free(fBytes);
+
+ fBytes = (uint8_t *)uprv_malloc(newSize);
+
+ if (fBytes == NULL)
+ {
+ return setToBogus();
+ }
+
+ uprv_memset(fBytes, 0, fCapacity);
+ fCapacity = newSize;
+ }
+
+ fBogus = FALSE;
+ fCount = newSize;
+ fHashCode = kInvalidHashCode;
+
+ return *this;
+}
+
+#ifdef U_USE_COLLATION_KEY_DEPRECATES
+// Create a copy of the byte array.
+uint8_t*
+CollationKey::toByteArray(int32_t& count) const
+{
+ uint8_t *result = (uint8_t*) uprv_malloc( sizeof(uint8_t) * fCount );
+
+ if (result == NULL)
+ {
+ count = 0;
+ }
+ else
+ {
+ count = fCount;
+ uprv_memcpy(result, fBytes, fCount);
+ }
+
+ return result;
+}
+#endif
+
+int32_t
+CollationKey::hashCode() const
+{
+ // (Cribbed from UnicodeString)
+ // We cache the hashCode; when it becomes invalid, due to any change to the
+ // string, we note this by setting it to kInvalidHashCode. [LIU]
+
+ // Note: This method is semantically const, but physically non-const.
+
+ if (fHashCode == kInvalidHashCode)
+ {
+ UHashTok key;
+ key.pointer = fBytes;
+ ((CollationKey *)this)->fHashCode = uhash_hashChars(key);
+#if 0
+ // We compute the hash by iterating sparsely over 64 (at most) characters
+ // spaced evenly through the string. For each character, we multiply the
+ // previous hash value by a prime number and add the new character in,
+ // in the manner of a additive linear congruential random number generator,
+ // thus producing a pseudorandom deterministic value which should be well
+ // distributed over the output range. [LIU]
+ const uint8_t *p = fBytes, *limit = fBytes + fCount;
+ int32_t inc = (fCount >= 256) ? fCount/128 : 2; // inc = max(fSize/64, 1);
+ int32_t hash = 0;
+
+ while (p < limit)
+ {
+ hash = ( hash * 37 ) + ((p[0] << 8) + p[1]);
+ p += inc;
+ }
+
+ // If we happened to get kInvalidHashCode, replace it with kEmptyHashCode
+ if (hash == kInvalidHashCode)
+ {
+ hash = kEmptyHashCode;
+ }
+
+ ((CollationKey *)this)->fHashCode = hash; // cast away const
+#endif
+ }
+
+ return fHashCode;
+}
+
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+ucol_keyHashCode(const uint8_t *key,
+ int32_t length)
+{
+ U_NAMESPACE_QUALIFIER CollationKey newKey(key, length);
+ return newKey.hashCode();
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/strmatch.cpp b/Build/source/libs/icu/icu-4.6/i18n/strmatch.cpp
new file mode 100644
index 00000000000..8286c7eaa07
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/strmatch.h b/Build/source/libs/icu/icu-4.6/i18n/strmatch.h
new file mode 100644
index 00000000000..90cba0c1d36
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/strmatch.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2001-2004, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 07/23/01 aliu Creation.
+ **********************************************************************
+ */
+#ifndef STRMATCH_H
+#define STRMATCH_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/unifunct.h"
+#include "unicode/unimatch.h"
+#include "unicode/unirepl.h"
+
+U_NAMESPACE_BEGIN
+
+class TransliterationRuleData;
+
+/**
+ * An object that matches a fixed input string, implementing the
+ * UnicodeMatcher API. This object also implements the
+ * UnicodeReplacer API, allowing it to emit the matched text as
+ * output. Since the match text may contain flexible match elements,
+ * such as UnicodeSets, the emitted text is not the match pattern, but
+ * instead a substring of the actual matched text. Following
+ * convention, the output text is the leftmost match seen up to this
+ * point.
+ *
+ * A StringMatcher may represent a segment, in which case it has a
+ * positive segment number. This affects how the matcher converts
+ * itself to a pattern but does not otherwise affect its function.
+ *
+ * A StringMatcher that is not a segment should not be used as a
+ * UnicodeReplacer.
+ */
+class StringMatcher : public UnicodeFunctor, public UnicodeMatcher, public UnicodeReplacer {
+
+ public:
+
+ /**
+ * Construct a matcher that matches the given pattern string.
+ * @param string the pattern to be matched, possibly containing
+ * stand-ins that represent nested UnicodeMatcher objects.
+ * @param start inclusive start index of text to be replaced
+ * @param limit exclusive end index of text to be replaced;
+ * must be greater than or equal to start
+ * @param segmentNum the segment number from 1..n, or 0 if this is
+ * not a segment.
+ * @param data context object mapping stand-ins to
+ * UnicodeMatcher objects.
+ */
+ StringMatcher(const UnicodeString& string,
+ int32_t start,
+ int32_t limit,
+ int32_t segmentNum,
+ const TransliterationRuleData& data);
+
+ /**
+ * Copy constructor
+ * @param o the object to be copied.
+ */
+ StringMatcher(const StringMatcher& o);
+
+ /**
+ * Destructor
+ */
+ virtual ~StringMatcher();
+
+ /**
+ * Implement UnicodeFunctor
+ * @return a copy of the object.
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ * @return the UnicodeMatcher point.
+ */
+ virtual UnicodeMatcher* toMatcher() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ * @return the UnicodeReplacer pointer.
+ */
+ virtual UnicodeReplacer* toReplacer() const;
+
+ /**
+ * Implement UnicodeMatcher
+ * @param text the text to be matched
+ * @param offset on input, the index into text at which to begin
+ * matching. On output, the limit of the matched text. The
+ * number of matched characters is the output value of offset
+ * minus the input value. Offset should always point to the
+ * HIGH SURROGATE (leading code unit) of a pair of surrogates,
+ * both on entry and upon return.
+ * @param limit the limit index of text to be matched. Greater
+ * than offset for a forward direction match, less than offset for
+ * a backward direction match. The last character to be
+ * considered for matching will be text.charAt(limit-1) in the
+ * forward direction or text.charAt(limit+1) in the backward
+ * direction.
+ * @param incremental if TRUE, then assume further characters may
+ * be inserted at limit and check for partial matching. Otherwise
+ * assume the text as given is complete.
+ * @return a match degree value indicating a full match, a partial
+ * match, or a mismatch. If incremental is FALSE then
+ * U_PARTIAL_MATCH should never be returned.
+ */
+ virtual UMatchDegree matches(const Replaceable& text,
+ int32_t& offset,
+ int32_t limit,
+ UBool incremental);
+
+ /**
+ * Implement UnicodeMatcher
+ * @param result Output param to receive the pattern.
+ * @param escapeUnprintable if True then escape the unprintable characters.
+ * @return A reference to 'result'.
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool escapeUnprintable = FALSE) const;
+
+ /**
+ * Implement UnicodeMatcher
+ * Returns TRUE if this matcher will match a character c, where c
+ * & 0xFF == v, at offset, in the forward direction (with limit >
+ * offset). This is used by <tt>RuleBasedTransliterator</tt> for
+ * indexing.
+ * @param v the given value
+ * @return TRUE if this matcher will match a character c,
+ * where c & 0xFF == v
+ */
+ virtual UBool matchesIndexValue(uint8_t v) const;
+
+ /**
+ * Implement UnicodeMatcher
+ */
+ virtual void addMatchSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * Implement UnicodeFunctor
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * Replace characters in 'text' from 'start' to 'limit' with the
+ * output text of this object. Update the 'cursor' parameter to
+ * give the cursor position and return the length of the
+ * replacement text.
+ *
+ * @param text the text to be matched
+ * @param start inclusive start index of text to be replaced
+ * @param limit exclusive end index of text to be replaced;
+ * must be greater than or equal to start
+ * @param cursor output parameter for the cursor position.
+ * Not all replacer objects will update this, but in a complete
+ * tree of replacer objects, representing the entire output side
+ * of a transliteration rule, at least one must update it.
+ * @return the number of 16-bit code units in the text replacing
+ * the characters at offsets start..(limit-1) in text
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor);
+
+ /**
+ * Returns a string representation of this replacer. If the
+ * result of calling this function is passed to the appropriate
+ * parser, typically TransliteratorParser, it will produce another
+ * replacer that is equal to this one.
+ * @param result the string to receive the pattern. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \\uxxxx or
+ * \\Uxxxxxxxx. Unprintable characters are defined by
+ * Utility.isUnprintable().
+ * @return a reference to 'result'.
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Remove any match data. This must be called before performing a
+ * set of matches with this segment.
+ */
+ void resetMatch();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * Union the set of all characters that may output by this object
+ * into the given set.
+ * @param toUnionTo the set into which to union the output characters
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const;
+
+ private:
+
+ /**
+ * The text to be matched.
+ */
+ UnicodeString pattern;
+
+ /**
+ * Context object that maps stand-ins to matcher and replacer
+ * objects.
+ */
+ const TransliterationRuleData* data;
+
+ /**
+ * The segment number, 1-based, or 0 if not a segment.
+ */
+ int32_t segmentNumber;
+
+ /**
+ * Start offset, in the match text, of the <em>rightmost</em>
+ * match.
+ */
+ int32_t matchStart;
+
+ /**
+ * Limit offset, in the match text, of the <em>rightmost</em>
+ * match.
+ */
+ int32_t matchLimit;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/strrepl.cpp b/Build/source/libs/icu/icu-4.6/i18n/strrepl.cpp
new file mode 100644
index 00000000000..4ae12b05c24
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/strrepl.h b/Build/source/libs/icu/icu-4.6/i18n/strrepl.h
new file mode 100644
index 00000000000..67a93e961f7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/strrepl.h
@@ -0,0 +1,165 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2004, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/21/2002 aliu Creation.
+**********************************************************************
+*/
+
+#ifndef STRREPL_H
+#define STRREPL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifunct.h"
+#include "unicode/unirepl.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+class TransliterationRuleData;
+
+/**
+ * A replacer that produces static text as its output. The text may
+ * contain transliterator stand-in characters that represent nested
+ * UnicodeReplacer objects, making it possible to encode a tree of
+ * replacers in a StringReplacer. A StringReplacer that contains such
+ * stand-ins is called a <em>complex</em> StringReplacer. A complex
+ * StringReplacer has a slower processing loop than a non-complex one.
+ * @author Alan Liu
+ */
+class StringReplacer : public UnicodeFunctor, public UnicodeReplacer {
+
+ private:
+
+ /**
+ * Output text, possibly containing stand-in characters that
+ * represent nested UnicodeReplacers.
+ */
+ UnicodeString output;
+
+ /**
+ * Cursor position. Value is ignored if hasCursor is false.
+ */
+ int32_t cursorPos;
+
+ /**
+ * True if this object outputs a cursor position.
+ */
+ UBool hasCursor;
+
+ /**
+ * A complex object contains nested replacers and requires more
+ * complex processing. StringReplacers are initially assumed to
+ * be complex. If no nested replacers are seen during processing,
+ * then isComplex is set to false, and future replacements are
+ * short circuited for better performance.
+ */
+ UBool isComplex;
+
+ /**
+ * Object that translates stand-in characters in 'output' to
+ * UnicodeReplacer objects.
+ */
+ const TransliterationRuleData* data;
+
+ public:
+
+ /**
+ * Construct a StringReplacer that sets the emits the given output
+ * text and sets the cursor to the given position.
+ * @param theOutput text that will replace input text when the
+ * replace() method is called. May contain stand-in characters
+ * that represent nested replacers.
+ * @param theCursorPos cursor position that will be returned by
+ * the replace() method
+ * @param theData transliterator context object that translates
+ * stand-in characters to UnicodeReplacer objects
+ */
+ StringReplacer(const UnicodeString& theOutput,
+ int32_t theCursorPos,
+ const TransliterationRuleData* theData);
+
+ /**
+ * Construct a StringReplacer that sets the emits the given output
+ * text and does not modify the cursor.
+ * @param theOutput text that will replace input text when the
+ * replace() method is called. May contain stand-in characters
+ * that represent nested replacers.
+ * @param theData transliterator context object that translates
+ * stand-in characters to UnicodeReplacer objects
+ */
+ StringReplacer(const UnicodeString& theOutput,
+ const TransliterationRuleData* theData);
+
+ /**
+ * Copy constructor.
+ */
+ StringReplacer(const StringReplacer& other);
+
+ /**
+ * Destructor
+ */
+ virtual ~StringReplacer();
+
+ /**
+ * Implement UnicodeFunctor
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ */
+ virtual UnicodeReplacer* toReplacer() const;
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor);
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Implement UnicodeReplacer
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * UnicodeFunctor API
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/stsearch.cpp b/Build/source/libs/icu/icu-4.6/i18n/stsearch.cpp
new file mode 100644
index 00000000000..447f95f3b34
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/taiwncal.cpp b/Build/source/libs/icu/icu-4.6/i18n/taiwncal.cpp
new file mode 100644
index 00000000000..4a895251df7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/taiwncal.h b/Build/source/libs/icu/icu-4.6/i18n/taiwncal.h
new file mode 100644
index 00000000000..fe6f89b1902
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tblcoll.cpp b/Build/source/libs/icu/icu-4.6/i18n/tblcoll.cpp
new file mode 100644
index 00000000000..15f5c490b63
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/tblcoll.cpp
@@ -0,0 +1,732 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2010, 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 ((!source) || (sourceLen == 0)) {
+ return sortkey.reset();
+ }
+
+ uint8_t *result;
+ int32_t resultLen = ucol_getSortKeyWithAllocation(ucollator,
+ source, sourceLen,
+ &result,
+ &status);
+ sortkey.adopt(result, resultLen);
+ return sortkey;
+}
+
+/**
+ * Return the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * @param order a collation order returned by previous or next.
+ * @return the maximum length of any expansion seuences ending with the
+ * specified order or 1 if collation order does not occur at the end of any
+ * expansion sequence.
+ * @see CollationElementIterator#getMaxExpansion
+ */
+int32_t RuleBasedCollator::getMaxExpansion(int32_t order) const
+{
+ uint8_t result;
+ UCOL_GETMAXEXPANSION(ucollator, (uint32_t)order, result);
+ return result;
+}
+
+uint8_t* RuleBasedCollator::cloneRuleData(int32_t &length,
+ UErrorCode &status)
+{
+ return ucol_cloneRuleData(ucollator, &length, &status);
+}
+
+
+int32_t RuleBasedCollator::cloneBinary(uint8_t *buffer, int32_t capacity, UErrorCode &status)
+{
+ return ucol_cloneBinary(ucollator, buffer, capacity, &status);
+}
+
+void RuleBasedCollator::setAttribute(UColAttribute attr,
+ UColAttributeValue value,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status))
+ return;
+ checkOwned();
+ ucol_setAttribute(ucollator, attr, value, &status);
+}
+
+UColAttributeValue RuleBasedCollator::getAttribute(UColAttribute attr,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status))
+ return UCOL_DEFAULT;
+ return ucol_getAttribute(ucollator, attr, &status);
+}
+
+uint32_t RuleBasedCollator::setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status) {
+ checkOwned();
+ return ucol_setVariableTop(ucollator, varTop, len, &status);
+}
+
+uint32_t RuleBasedCollator::setVariableTop(const UnicodeString varTop, UErrorCode &status) {
+ checkOwned();
+ return ucol_setVariableTop(ucollator, varTop.getBuffer(), varTop.length(), &status);
+}
+
+void RuleBasedCollator::setVariableTop(const uint32_t varTop, UErrorCode &status) {
+ checkOwned();
+ ucol_restoreVariableTop(ucollator, varTop, &status);
+}
+
+uint32_t RuleBasedCollator::getVariableTop(UErrorCode &status) const {
+ return ucol_getVariableTop(ucollator, &status);
+}
+
+Collator* RuleBasedCollator::safeClone(void)
+{
+ UErrorCode intStatus = U_ZERO_ERROR;
+ int32_t buffersize = U_COL_SAFECLONE_BUFFERSIZE;
+ UCollator *ucol = ucol_safeClone(ucollator, NULL, &buffersize,
+ &intStatus);
+ if (U_FAILURE(intStatus)) {
+ return NULL;
+ }
+
+ RuleBasedCollator *result = new RuleBasedCollator();
+ // 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)
+{
+ ucol_setReorderCodes(ucollator, reorderCodes, reorderCodesLength, &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.6/i18n/timezone.cpp b/Build/source/libs/icu/icu-4.6/i18n/timezone.cpp
new file mode 100644
index 00000000000..777bee77ade
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/timezone.cpp
@@ -0,0 +1,1387 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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"
+
+#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 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 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;
+
+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;
+
+ if (LOCK) {
+ umtx_destroy(&LOCK);
+ LOCK = NULL;
+ }
+ if (TZSET_LOCK) {
+ umtx_destroy(&TZSET_LOCK);
+ TZSET_LOCK = NULL;
+ }
+
+ return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+/**
+ * The Olson data is stored the "zoneinfo" resource bundle.
+ * Sub-resources are organized into three ranges of data: Zones, final
+ * rules, and country tables. There is also a meta-data resource
+ * which has 3 integers: The number of zones, rules, and countries,
+ * respectively. The country count includes the non-country 'Default'.
+ */
+static int32_t OLSON_ZONE_COUNT = 0; // count of zones
+
+/**
+ * Given a pointer to an open "zoneinfo" resource, load up the Olson
+ * meta-data. Return TRUE if successful.
+ */
+static UBool getOlsonMeta(const UResourceBundle* top) {
+ if (OLSON_ZONE_COUNT == 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ ures_getByKey(top, kZONES, &res, &ec);
+ if(U_SUCCESS(ec)) {
+ OLSON_ZONE_COUNT = ures_getSize(&res);
+ U_DEBUG_TZ_MSG(("OZC%d\n",OLSON_ZONE_COUNT));
+ }
+ ures_close(&res);
+ }
+ return (OLSON_ZONE_COUNT > 0);
+}
+
+/**
+ * Load up the Olson meta-data. Return TRUE if successful.
+ */
+static UBool getOlsonMeta() {
+ if (OLSON_ZONE_COUNT == 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ if (U_SUCCESS(ec)) {
+ getOlsonMeta(top);
+ }
+ ures_close(top);
+ }
+ return (OLSON_ZONE_COUNT > 0);
+}
+
+static int32_t findInStringArray(UResourceBundle* array, const UnicodeString& id, UErrorCode &status)
+{
+ UnicodeString copy;
+ const UChar *u;
+ int32_t len;
+
+ int32_t start = 0;
+ int32_t limit = ures_getSize(array);
+ int32_t mid;
+ int32_t lastMid = INT32_MAX;
+ if(U_FAILURE(status) || (limit < 1)) {
+ return -1;
+ }
+ U_DEBUG_TZ_MSG(("fisa: Looking for %s, between %d and %d\n", U_DEBUG_TZ_STR(UnicodeString(id).getTerminatedBuffer()), start, limit));
+
+ for (;;) {
+ mid = (int32_t)((start + limit) / 2);
+ if (lastMid == mid) { /* Have we moved? */
+ break; /* We haven't moved, and it wasn't found. */
+ }
+ lastMid = mid;
+ u = ures_getStringByIndex(array, mid, &len, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit));
+ copy.setTo(TRUE, u, len);
+ int r = id.compare(copy);
+ if(r==0) {
+ U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid));
+ return mid;
+ } else if(r<0) {
+ limit = mid;
+ } else {
+ start = mid;
+ }
+ }
+ U_DEBUG_TZ_MSG(("fisa: not found\n"));
+ return -1;
+}
+
+/**
+ * Fetch a specific zone by name. Replaces the getByKey call.
+ * @param top Top timezone resource
+ * @param id Time zone ID
+ * @param oldbundle Bundle for reuse (or NULL). see 'ures_open()'
+ * @return the zone's bundle if found, or undefined if error. Reuses oldbundle.
+ */
+static UResourceBundle* getZoneByName(const UResourceBundle* top, const UnicodeString& id, UResourceBundle *oldbundle, UErrorCode& status) {
+ // load the Rules object
+ UResourceBundle *tmp = ures_getByKey(top, kNAMES, NULL, &status);
+
+ // search for the string
+ int32_t idx = findInStringArray(tmp, id, status);
+
+ if((idx == -1) && U_SUCCESS(status)) {
+ // not found
+ status = U_MISSING_RESOURCE_ERROR;
+ //ures_close(oldbundle);
+ //oldbundle = NULL;
+ } else {
+ U_DEBUG_TZ_MSG(("gzbn: oldbundle= size %d, type %d, %s\n", ures_getSize(tmp), ures_getType(tmp), u_errorName(status)));
+ tmp = ures_getByKey(top, kZONES, tmp, &status); // get Zones object from top
+ U_DEBUG_TZ_MSG(("gzbn: loaded ZONES, size %d, type %d, path %s %s\n", ures_getSize(tmp), ures_getType(tmp), ures_getPath(tmp), u_errorName(status)));
+ oldbundle = ures_getByIndex(tmp, idx, oldbundle, &status); // get nth Zone object
+ U_DEBUG_TZ_MSG(("gzbn: loaded z#%d, size %d, type %d, path %s, %s\n", idx, ures_getSize(oldbundle), ures_getType(oldbundle), ures_getPath(oldbundle), u_errorName(status)));
+ }
+ ures_close(tmp);
+ if(U_FAILURE(status)) {
+ //ures_close(oldbundle);
+ return NULL;
+ } else {
+ return oldbundle;
+ }
+}
+
+
+UResourceBundle* TimeZone::loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode& status) {
+ char key[64];
+ ruleid.extract(0, sizeof(key)-1, key, (int32_t)sizeof(key)-1, US_INV);
+ U_DEBUG_TZ_MSG(("loadRule(%s)\n", key));
+ UResourceBundle *r = ures_getByKey(top, kRULES, oldbundle, &status);
+ U_DEBUG_TZ_MSG(("loadRule(%s) -> kRULES [%s]\n", key, u_errorName(status)));
+ r = ures_getByKey(r, key, r, &status);
+ U_DEBUG_TZ_MSG(("loadRule(%s) -> item [%s]\n", key, u_errorName(status)));
+ return r;
+}
+
+/**
+ * Given an ID, open the appropriate resource for the given time zone.
+ * Dereference aliases if necessary.
+ * @param id zone id
+ * @param res resource, which must be ready for use (initialized but not open)
+ * @param ec input-output error code
+ * @return top-level resource bundle
+ */
+static UResourceBundle* openOlsonResource(const UnicodeString& id,
+ UResourceBundle& res,
+ UErrorCode& ec)
+{
+#if U_DEBUG_TZ
+ char buf[128];
+ id.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
+#endif
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ U_DEBUG_TZ_MSG(("pre: res sz=%d\n", ures_getSize(&res)));
+ /* &res = */ getZoneByName(top, id, &res, ec);
+ // Dereference if this is an alias. Docs say result should be 1
+ // but it is 0 in 2.8 (?).
+ U_DEBUG_TZ_MSG(("Loading zone '%s' (%s, size %d) - %s\n", buf, ures_getKey((UResourceBundle*)&res), ures_getSize(&res), u_errorName(ec)));
+ if (ures_getType(&res) == URES_INT && getOlsonMeta(top)) {
+ int32_t deref = ures_getInt(&res, &ec) + 0;
+ U_DEBUG_TZ_MSG(("getInt: %s - type is %d\n", u_errorName(ec), ures_getType(&res)));
+ UResourceBundle *ares = ures_getByKey(top, kZONES, NULL, &ec); // dereference Zones section
+ ures_getByIndex(ares, deref, &res, &ec);
+ ures_close(ares);
+ U_DEBUG_TZ_MSG(("alias to #%d (%s) - %s\n", deref, "??", u_errorName(ec)));
+ } else {
+ U_DEBUG_TZ_MSG(("not an alias - size %d\n", ures_getSize(&res)));
+ }
+ U_DEBUG_TZ_MSG(("%s - final status is %s\n", buf, u_errorName(ec)));
+ return top;
+}
+
+// -------------------------------------
+
+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 GMT"));
+ const TimeZone* temptz = getGMT();
+ if (temptz == NULL) {
+ result = NULL;
+ } else {
+ result = temptz->clone();
+ }
+ }
+ return result;
+}
+
+/**
+ * Lookup the given name in our system zone table. If found,
+ * instantiate a new zone of that name and return it. If not
+ * found, return 0.
+ */
+TimeZone*
+TimeZone::createSystemTimeZone(const UnicodeString& id) {
+ TimeZone* z = 0;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec)));
+ UResourceBundle *top = openOlsonResource(id, res, ec);
+ U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec)));
+ if (U_SUCCESS(ec)) {
+ z = new OlsonTimeZone(top, &res, ec);
+ if (z) {
+ z->setID(id);
+ } else {
+ U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
+ }
+ }
+ ures_close(&res);
+ ures_close(top);
+ if (U_FAILURE(ec)) {
+ U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec)));
+ delete z;
+ z = 0;
+ }
+ return z;
+}
+
+// -------------------------------------
+
+/**
+ * Initialize DEFAULT_ZONE from the system default time zone. The
+ * caller should confirm that DEFAULT_ZONE is NULL before calling.
+ * Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
+ * returns NULL.
+ *
+ * Must be called OUTSIDE mutex.
+ */
+void
+TimeZone::initDefault()
+{
+ // We access system timezone data through TPlatformUtilities,
+ // including tzset(), timezone, and tzname[].
+ int32_t rawOffset = 0;
+ const char *hostID;
+
+ // First, try to create a system timezone, based
+ // on the string ID in tzname[0].
+ {
+ // NOTE: Local mutex here. TimeZone mutex below
+ // mutexed to avoid threading issues in the platform functions.
+ // Some of the locale/timezone OS functions may not be thread safe,
+ // so the intent is that any setting from anywhere within ICU
+ // happens while the ICU mutex is held.
+ // The operating system might actually use ICU to implement timezones.
+ // So we may have ICU calling ICU here, like on AIX.
+ // In order to prevent a double lock of a non-reentrant mutex in a
+ // different part of ICU, we use TZSET_LOCK to allow only one instance
+ // of ICU to query these thread unsafe OS functions at any given time.
+ Mutex lock(&TZSET_LOCK);
+
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ uprv_tzset(); // Initialize tz... system data
+
+ // Get the timezone ID from the host. This function should do
+ // any required host-specific remapping; e.g., on Windows this
+ // function maps the Date and Time control panel setting to an
+ // ICU timezone ID.
+ hostID = uprv_tzname(0);
+
+ // Invert sign because UNIX semantics are backwards
+ rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
+ }
+
+ UBool initialized;
+ UMTX_CHECK(&LOCK, (DEFAULT_ZONE != NULL), initialized);
+ if (initialized) {
+ /* Hrmph? Either a race condition happened, or tzset initialized ICU. */
+ return;
+ }
+
+ TimeZone* default_zone = NULL;
+
+ /* Make sure that the string is NULL terminated to prevent BoundsChecker/Purify warnings. */
+ UnicodeString hostStrID(hostID, -1, US_INV);
+ hostStrID.append((UChar)0);
+ hostStrID.truncate(hostStrID.length()-1);
+ default_zone = createSystemTimeZone(hostStrID);
+
+#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
+ // iff the zone data could not be loaded.
+ int32_t* map;
+ int32_t len;
+ int32_t pos;
+
+ UBool getID(int32_t i) {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t idLen = 0;
+ const UChar* id = NULL;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ top = ures_getByKey(top, kNAMES, top, &ec); // dereference Zones section
+ id = ures_getStringByIndex(top, i, &idLen, &ec);
+ if(U_FAILURE(ec)) {
+ unistr.truncate(0);
+ }
+ else {
+ unistr.fastCopyFrom(UnicodeString(TRUE, id, idLen));
+ }
+ ures_close(top);
+ return U_SUCCESS(ec);
+ }
+
+public:
+ TZEnumeration() : map(NULL), len(0), pos(0) {
+ if (getOlsonMeta()) {
+ len = OLSON_ZONE_COUNT;
+ }
+ }
+
+ TZEnumeration(int32_t rawOffset) : map(NULL), len(0), pos(0) {
+ if (!getOlsonMeta()) {
+ return;
+ }
+
+ // Allocate more space than we'll need. The end of the array will
+ // be blank.
+ map = (int32_t*)uprv_malloc(OLSON_ZONE_COUNT * sizeof(int32_t));
+ if (map == 0) {
+ return;
+ }
+
+ uprv_memset(map, 0, sizeof(int32_t) * OLSON_ZONE_COUNT);
+
+ UnicodeString s;
+ for (int32_t i=0; i<OLSON_ZONE_COUNT; ++i) {
+ if (getID(i)) {
+ // This is VERY inefficient.
+ TimeZone* z = TimeZone::createTimeZone(unistr);
+ // Make sure we get back the ID we wanted (if the ID is
+ // invalid we get back GMT).
+ if (z != 0 && z->getID(s) == unistr &&
+ z->getRawOffset() == rawOffset) {
+ map[len++] = i;
+ }
+ delete z;
+ }
+ }
+ }
+
+ TZEnumeration(const char* country) : map(NULL), len(0), pos(0) {
+ if (!getOlsonMeta()) {
+ return;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
+ ures_getByKey(res, kREGIONS, res, &ec);
+ if (U_SUCCESS(ec) && ures_getType(res) == URES_ARRAY) {
+ UChar uCountry[] = {0, 0, 0, 0};
+ if (country) {
+ u_charsToUChars(country, uCountry, 2);
+ } else {
+ u_strcpy(uCountry, WORLD);
+ }
+
+ // count matches
+ int32_t count = 0;
+ int32_t i;
+ const UChar *region;
+ for (i = 0; i < ures_getSize(res); i++) {
+ region = ures_getStringByIndex(res, i, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (u_strcmp(uCountry, region) == 0) {
+ count++;
+ }
+ }
+
+ if (count > 0) {
+ map = (int32_t*)uprv_malloc(sizeof(int32_t) * count);
+ if (map != NULL) {
+ int32_t idx = 0;
+ for (i = 0; i < ures_getSize(res); i++) {
+ region = ures_getStringByIndex(res, i, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ if (u_strcmp(uCountry, region) == 0) {
+ map[idx++] = i;
+ }
+ }
+ if (U_SUCCESS(ec)) {
+ len = count;
+ } else {
+ uprv_free(map);
+ map = NULL;
+ }
+ } else {
+ U_DEBUG_TZ_MSG(("Failed to load tz for region %s: %s\n", country, u_errorName(ec)));
+ }
+ }
+ }
+ ures_close(res);
+ }
+
+ TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(NULL), len(0), pos(0) {
+ if(other.len > 0) {
+ if(other.map != NULL) {
+ map = (int32_t *)uprv_malloc(other.len * sizeof(int32_t));
+ if(map != NULL) {
+ len = other.len;
+ uprv_memcpy(map, other.map, len * sizeof(int32_t));
+ pos = other.pos;
+ }
+ } else {
+ len = other.len;
+ pos = other.pos;
+ }
+ }
+ }
+
+ virtual ~TZEnumeration() {
+ uprv_free(map);
+ }
+
+ virtual StringEnumeration *clone() const {
+ return new TZEnumeration(*this);
+ }
+
+ virtual int32_t count(UErrorCode& status) const {
+ return U_FAILURE(status) ? 0 : len;
+ }
+
+ virtual const UnicodeString* snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < len) {
+ getID((map == 0) ? pos : map[pos]);
+ ++pos;
+ return &unistr;
+ }
+ return 0;
+ }
+
+ virtual void reset(UErrorCode& /*status*/) {
+ pos = 0;
+ }
+
+public:
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TZEnumeration)
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration() {
+ return new TZEnumeration();
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration(int32_t rawOffset) {
+ return new TZEnumeration(rawOffset);
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration(const char* country) {
+ return new TZEnumeration(country);
+}
+
+// ---------------------------------------
+
+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 && getOlsonMeta()) {
+ zone = v[index];
+ }
+ }
+ ures_close(&r);
+ }
+ ures_close(&res);
+ if (zone >= 0) {
+ UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section
+ if (U_SUCCESS(ec)) {
+ int32_t idLen = 0;
+ const UChar* id = ures_getStringByIndex(ares, zone, &idLen, &ec);
+ result.fastCopyFrom(UnicodeString(TRUE, id, idLen));
+ U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec)));
+ }
+ ures_close(ares);
+ }
+ ures_close(top);
+#if defined(U_DEBUG_TZ)
+ if(result.length() ==0) {
+ U_DEBUG_TZ_MSG(("equiv [__, #%d] -> 0 (%s)\n", index, u_errorName(ec)));
+ }
+#endif
+ return result;
+}
+
+// ---------------------------------------
+
+// These two methods are used by ZoneMeta class only.
+
+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) {
+ const UChar *result = WORLD;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
+
+ // resolve zone index by name
+ UResourceBundle *res = ures_getByKey(rb, kNAMES, NULL, &ec);
+ int32_t idx = findInStringArray(res, id, ec);
+
+ // get region mapping
+ ures_getByKey(rb, kREGIONS, res, &ec);
+ const UChar *tmp = ures_getStringByIndex(res, idx, NULL, &ec);
+ if (U_SUCCESS(ec)) {
+ result = tmp;
+ }
+
+ ures_close(res);
+ ures_close(rb);
+
+ return result;
+}
+
+// ---------------------------------------
+
+
+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);
+
+ // 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;
+ }
+ ZoneMeta::getCanonicalSystemID(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.6/i18n/titletrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/titletrn.cpp
new file mode 100644
index 00000000000..76c17d1bad7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/titletrn.h b/Build/source/libs/icu/icu-4.6/i18n/titletrn.h
new file mode 100644
index 00000000000..a093152b66c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tmunit.cpp b/Build/source/libs/icu/icu-4.6/i18n/tmunit.cpp
new file mode 100644
index 00000000000..fb31e252091
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tmutamt.cpp b/Build/source/libs/icu/icu-4.6/i18n/tmutamt.cpp
new file mode 100644
index 00000000000..382c7ffd292
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tmutfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/tmutfmt.cpp
new file mode 100644
index 00000000000..01ed795c795
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/tmutfmt.cpp
@@ -0,0 +1,874 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2010, 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 "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(), kFull, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(locale, kFull, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(locale, style, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
+: MeasureFormat(other),
+ fNumberFormat(NULL),
+ fPluralRules(NULL),
+ fStyle(kFull)
+{
+ 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 (EStyle style = kFull; style < kTotal; style = (EStyle)(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 ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) {
+ resultNumber = 0;
+ } else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) {
+ resultNumber = 1;
+ } else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) {
+ 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, EStyle style, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (style < kFull || style > kAbbreviate) {
+ 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(kFull, gUnitsTag, err);
+ checkConsistency(kFull, gUnitsTag, err);
+ readFromCurrentLocale(kAbbreviate, gShortUnitsTag, err);
+ checkConsistency(kAbbreviate, 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(EStyle 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 UChar* pattern;
+ const char* pluralCount;
+ int32_t ptLength;
+ for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
+ // resource of count to pattern
+ pattern = ures_getNextString(countsToPatternRB, &ptLength,
+ &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);
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
+ if (formatters == NULL) {
+ formatters = (MessageFormat**)uprv_malloc(kTotal*sizeof(MessageFormat*));
+ formatters[kFull] = NULL;
+ formatters[kAbbreviate] = NULL;
+ countToPatterns->put(pluralCount, 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(EStyle 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 char* pluralCount;
+ while ((pluralCount = keywords->next(NULL, 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();
+ searchInLocaleChain(style, key, localeName,
+ (TimeUnit::UTimeUnitFields)i,
+ pluralCount, pluralCount,
+ 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(EStyle style, const char* key, const char* localeName,
+ TimeUnit::UTimeUnitFields srcTimeUnitField,
+ const char* 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(pattern, 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(kTotal*sizeof(MessageFormat*));
+ formatters[kFull] = NULL;
+ formatters[kAbbreviate] = 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;
+ if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, 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(kTotal*sizeof(MessageFormat*));
+ formatters[kFull] = NULL;
+ formatters[kAbbreviate] = 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[kFull]->setFormat(0, format);
+ pattern[kAbbreviate]->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[kFull];
+ delete value[kAbbreviate];
+ //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(kTotal*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;
+ }
+ 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.6/i18n/tolowtrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/tolowtrn.cpp
new file mode 100644
index 00000000000..c93f4d0eff8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tolowtrn.h b/Build/source/libs/icu/icu-4.6/i18n/tolowtrn.h
new file mode 100644
index 00000000000..564b215a728
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/toupptrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/toupptrn.cpp
new file mode 100644
index 00000000000..4b7c7d06aca
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/toupptrn.h b/Build/source/libs/icu/icu-4.6/i18n/toupptrn.h
new file mode 100644
index 00000000000..77799acbfd6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/translit.cpp b/Build/source/libs/icu/icu-4.6/i18n/translit.cpp
new file mode 100644
index 00000000000..84364796af9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/transreg.cpp b/Build/source/libs/icu/icu-4.6/i18n/transreg.cpp
new file mode 100644
index 00000000000..8e1d4f431fd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/transreg.h b/Build/source/libs/icu/icu-4.6/i18n/transreg.h
new file mode 100644
index 00000000000..483e74f4560
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tridpars.cpp b/Build/source/libs/icu/icu-4.6/i18n/tridpars.cpp
new file mode 100644
index 00000000000..cf9fd3fb5b6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tridpars.h b/Build/source/libs/icu/icu-4.6/i18n/tridpars.h
new file mode 100644
index 00000000000..1f2268fb111
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tzrule.cpp b/Build/source/libs/icu/icu-4.6/i18n/tzrule.cpp
new file mode 100644
index 00000000000..e54b9b875fc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/tztrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/tztrans.cpp
new file mode 100644
index 00000000000..f795e409288
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucal.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucal.cpp
new file mode 100644
index 00000000000..5a659e518a6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucal.cpp
@@ -0,0 +1,687 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-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/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_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);
+}
+
+
+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.6/i18n/ucln_in.c b/Build/source/libs/icu/icu-4.6/i18n/ucln_in.c
new file mode 100644
index 00000000000..cce5890d452
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucln_in.h b/Build/source/libs/icu/icu-4.6/i18n/ucln_in.h
new file mode 100644
index 00000000000..82de8389bc4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucln_in.h
@@ -0,0 +1,59 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2009, 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_ZONEMETA,
+ UCLN_I18N_ZSFORMAT,
+ UCLN_I18N_TIMEZONE,
+ UCLN_I18N_PLURAL_RULE,
+ UCLN_I18N_CURRENCY,
+ UCLN_I18N_NUMFMT,
+ 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_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.6/i18n/ucol.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol.cpp
new file mode 100644
index 00000000000..18de3573996
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol.cpp
@@ -0,0 +1,8593 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2010, 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/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;
+ uint8_t *image;
+ UChar *rules;
+ UBool colAllocated = FALSE;
+ UBool imageAllocated = FALSE;
+
+ if (status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+ if ((stackBuffer && !pBufferSize) || !coll){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ if (coll->rules && coll->freeRulesOnClose) {
+ rulesSize = (int32_t)(coll->rulesLength + 1)*sizeof(UChar);
+ rulesPadding = (int32_t)(bufferSizeNeeded % sizeof(UChar));
+ bufferSizeNeeded += rulesSize + rulesPadding;
+ }
+
+ if (stackBuffer && *pBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */
+ *pBufferSize = bufferSizeNeeded;
+ return 0;
+ }
+
+ /* Pointers on 64-bit platforms need to be aligned
+ * on a 64-bit boundry in memory.
+ */
+ if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
+ int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars);
+ if (*pBufferSize > offsetUp) {
+ *pBufferSize -= offsetUp;
+ stackBufferChars += offsetUp;
+ }
+ else {
+ /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
+ *pBufferSize = 1;
+ }
+ }
+ stackBuffer = (void *)stackBufferChars;
+
+ if (stackBuffer == NULL || *pBufferSize < bufferSizeNeeded) {
+ /* allocate one here...*/
+ stackBufferChars = (char *)uprv_malloc(bufferSizeNeeded);
+ // 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);
+ {
+ 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;
+ }
+
+ 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) {
+ uprv_free(coll->leadBytePermutationTable);
+ }
+ if(coll->reorderCodes != NULL) {
+ 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->reorderCodes = NULL;
+ result->reorderCodesLength = 0;
+ result->leadBytePermutationTable = NULL;
+
+ /* 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;
+
+ 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);
+ }
+ }
+ }
+ 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;
+
+ /*
+ 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);
+ }
+ }
+ }
+ }
+
+ 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);
+
+ source->fcdPosition = source->pos; // Indicate where to continue in main input string
+ // after exhausting the writableBuffer
+ 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
+ /*
+ Move the Jamos into the
+ normalization buffer
+ */
+ UChar *tempbuffer = source->writableBuffer.getBuffer(5);
+ int32_t tempbufferLength;
+ 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) {
+ source->fcdPosition = NULL;
+ } else {
+ source->fcdPosition = source->pos-1;
+ }
+
+ 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 */
+/* However, it is used only when stack buffers are not sufficiently big, and then we're messed up performance wise */
+/* anyway */
+static
+uint8_t *reallocateBuffer(uint8_t **secondaries, uint8_t *secStart, uint8_t *second, uint32_t *secSize, uint32_t newSize, UErrorCode *status) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, ".");
+#endif
+ uint8_t *newStart = NULL;
+ uint32_t offset = (uint32_t)(*secondaries-secStart);
+
+ if(secStart==second) {
+ newStart=(uint8_t*)uprv_malloc(newSize);
+ if(newStart==NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(newStart, secStart, *secondaries-secStart);
+ } else {
+ newStart=(uint8_t*)uprv_realloc(secStart, newSize);
+ if(newStart==NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ /* Since we're reallocating, return original reference so we don't loose it. */
+ return secStart;
+ }
+ }
+ *secondaries=newStart+offset;
+ *secSize=newSize;
+ return newStart;
+}
+
+
+/* This should really be a macro */
+/* This function is used to reverse parts of a buffer. We need this operation when doing continuation */
+/* secondaries in French */
+/*
+void uprv_ucol_reverse_buffer(uint8_t *start, uint8_t *end) {
+ uint8_t temp;
+ while(start<end) {
+ temp = *start;
+ *start++ = *end;
+ *end-- = temp;
+ }
+}
+*/
+
+#define uprv_ucol_reverse_buffer(TYPE, start, end) { \
+ TYPE tempA; \
+while((start)<(end)) { \
+ tempA = *(start); \
+ *(start)++ = *(end); \
+ *(end)-- = tempA; \
+} \
+}
+
+/****************************************************************************/
+/* Following are the sortkey generation functions */
+/* */
+/****************************************************************************/
+
+/**
+ * Merge two sort keys.
+ * This is useful, for example, to combine sort keys from first and last names
+ * to sort such pairs.
+ * Merged sort keys consider on each collation level the first part first entirely,
+ * then the second one.
+ * It is possible to merge multiple sort keys by consecutively merging
+ * another one with the intermediate result.
+ *
+ * The length of the merge result is the sum of the lengths of the input sort keys
+ * minus 1.
+ *
+ * @param src1 the first sort key
+ * @param src1Length the length of the first sort key, including the zero byte at the end;
+ * can be -1 if the function is to find the length
+ * @param src2 the second sort key
+ * @param src2Length the length of the second sort key, including the zero byte at the end;
+ * can be -1 if the function is to find the length
+ * @param dest the buffer where the merged sort key is written,
+ * can be NULL if destCapacity==0
+ * @param destCapacity the number of bytes in the dest buffer
+ * @return the length of the merged sort key, src1Length+src2Length-1;
+ * can be larger than destCapacity, or 0 if an error occurs (only for illegal arguments),
+ * in which cases the contents of dest is undefined
+ *
+ * @draft
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_mergeSortkeys(const uint8_t *src1, int32_t src1Length,
+ const uint8_t *src2, int32_t src2Length,
+ uint8_t *dest, int32_t destCapacity) {
+ int32_t destLength;
+ uint8_t b;
+
+ /* check arguments */
+ if( src1==NULL || src1Length<-2 || src1Length==0 || (src1Length>0 && src1[src1Length-1]!=0) ||
+ src2==NULL || src2Length<-2 || src2Length==0 || (src2Length>0 && src2[src2Length-1]!=0) ||
+ destCapacity<0 || (destCapacity>0 && dest==NULL)
+ ) {
+ /* error, attempt to write a zero byte and return 0 */
+ if(dest!=NULL && destCapacity>0) {
+ *dest=0;
+ }
+ return 0;
+ }
+
+ /* check lengths and capacity */
+ if(src1Length<0) {
+ src1Length=(int32_t)uprv_strlen((const char *)src1)+1;
+ }
+ if(src2Length<0) {
+ src2Length=(int32_t)uprv_strlen((const char *)src2)+1;
+ }
+
+ destLength=src1Length+src2Length-1;
+ if(destLength>destCapacity) {
+ /* the merged sort key does not fit into the destination */
+ return destLength;
+ }
+
+ /* merge the sort keys with the same number of levels */
+ while(*src1!=0 && *src2!=0) { /* while both have another level */
+ /* copy level from src1 not including 00 or 01 */
+ while((b=*src1)>=2) {
+ ++src1;
+ *dest++=b;
+ }
+
+ /* add a 02 merge separator */
+ *dest++=2;
+
+ /* copy level from src2 not including 00 or 01 */
+ while((b=*src2)>=2) {
+ ++src2;
+ *dest++=b;
+ }
+
+ /* if both sort keys have another level, then add a 01 level separator and continue */
+ if(*src1==1 && *src2==1) {
+ ++src1;
+ ++src2;
+ *dest++=1;
+ }
+ }
+
+ /*
+ * here, at least one sort key is finished now, but the other one
+ * might have some contents left from containing more levels;
+ * that contents is just appended to the result
+ */
+ if(*src1!=0) {
+ /* src1 is not finished, therefore *src2==0, and src1 is appended */
+ src2=src1;
+ }
+ /* append src2, "the other, unfinished sort key" */
+ uprv_strcpy((char *)dest, (const char *)src2);
+
+ /* trust that neither sort key contained illegally embedded zero bytes */
+ return destLength;
+}
+
+/* sortkey API */
+U_CAPI int32_t U_EXPORT2
+ucol_getSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t *result,
+ int32_t resultLength)
+{
+ UTRACE_ENTRY(UTRACE_UCOL_GET_SORTKEY);
+ if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
+ UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source string = %vh ", coll, source,
+ ((sourceLength==-1 && source!=NULL) ? u_strlen(source) : sourceLength));
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t keySize = 0;
+
+ if(source != NULL) {
+ // source == NULL is actually an error situation, but we would need to
+ // have an error code to return it. Until we introduce a new
+ // API, it stays like this
+
+ /* this uses the function pointer that is set in updateinternalstate */
+ /* currently, there are two funcs: */
+ /*ucol_calcSortKey(...);*/
+ /*ucol_calcSortKeySimpleTertiary(...);*/
+
+ keySize = coll->sortKeyGen(coll, source, sourceLength, &result, resultLength, FALSE, &status);
+ //if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR && result && resultLength > 0) {
+ // That's not good. Something unusual happened.
+ // We don't know how much we initialized before we failed.
+ // NULL terminate for safety.
+ // We have no way say that we have generated a partial sort key.
+ //result[0] = 0;
+ //keySize = 0;
+ //}
+ }
+ UTRACE_DATA2(UTRACE_VERBOSE, "Sort Key = %vb", result, keySize);
+ UTRACE_EXIT_STATUS(status);
+ return keySize;
+}
+
+/* this function is called by the C++ API for sortkey generation */
+U_CFUNC int32_t
+ucol_getSortKeyWithAllocation(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ uint8_t **pResult,
+ UErrorCode *pErrorCode) {
+ *pResult = 0;
+ return coll->sortKeyGen(coll, source, sourceLength, pResult, 0, TRUE, pErrorCode);
+}
+
+#define UCOL_FSEC_BUF_SIZE 256
+
+// 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;
+}
+
+/* This function tries to get the size of a sortkey. It will be invoked if the size of resulting buffer is 0 */
+/* or if we run out of space while making a sortkey and want to return ASAP */
+int32_t ucol_getSortKeySize(const UCollator *coll, collIterate *s, int32_t currentSize, UColAttributeValue strength, int32_t len) {
+ UErrorCode status = U_ZERO_ERROR;
+ //const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)coll->UCA->image + coll->image->UCAConsts);
+ uint8_t compareSec = (uint8_t)((strength >= UCOL_SECONDARY)?0:0xFF);
+ uint8_t compareTer = (uint8_t)((strength >= UCOL_TERTIARY)?0:0xFF);
+ uint8_t compareQuad = (uint8_t)((strength >= UCOL_QUATERNARY)?0:0xFF);
+ UBool compareIdent = (strength == UCOL_IDENTICAL);
+ UBool doCase = (coll->caseLevel == UCOL_ON);
+ UBool shifted = (coll->alternateHandling == UCOL_SHIFTED);
+ //UBool qShifted = shifted && (compareQuad == 0);
+ UBool doHiragana = (coll->hiraganaQ == UCOL_ON) && (compareQuad == 0);
+ UBool isFrenchSec = (coll->frenchCollation == UCOL_ON) && (compareSec == 0);
+ uint8_t fSecsBuff[UCOL_FSEC_BUF_SIZE];
+ uint8_t *fSecs = fSecsBuff;
+ uint32_t fSecsLen = 0, fSecsMaxLen = UCOL_FSEC_BUF_SIZE;
+ uint8_t *frenchStartPtr = NULL, *frenchEndPtr = NULL;
+
+ uint32_t variableTopValue = coll->variableTopValue;
+ uint8_t UCOL_COMMON_BOT4 = (uint8_t)((coll->variableTopValue>>8)+1);
+ if(doHiragana) {
+ UCOL_COMMON_BOT4++;
+ /* allocate one more space for hiragana */
+ }
+ uint8_t UCOL_BOT_COUNT4 = (uint8_t)(0xFF - UCOL_COMMON_BOT4);
+
+ uint32_t order = UCOL_NO_MORE_CES;
+ uint8_t primary1 = 0;
+ uint8_t primary2 = 0;
+ uint8_t secondary = 0;
+ uint8_t tertiary = 0;
+ int32_t caseShift = 0;
+ uint32_t c2 = 0, c3 = 0, c4 = 0; /* variables for compression */
+
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+
+ UBool wasShifted = FALSE;
+ UBool notIsContinuation = FALSE;
+ uint8_t leadPrimary = 0;
+
+
+ for(;;) {
+ order = ucol_IGetNextCE(coll, s, &status);
+ if(order == UCOL_NO_MORE_CES) {
+ break;
+ }
+
+ if(order == 0) {
+ continue;
+ }
+
+ notIsContinuation = !isContinuation(order);
+
+
+ if(notIsContinuation) {
+ tertiary = (uint8_t)((order & UCOL_BYTE_SIZE_MASK));
+ } else {
+ tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
+ }
+ secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(order >> 8);
+
+ /* no need to permute since the actual code values don't matter
+ if (coll->leadBytePermutationTable != NULL && notIsContinuation) {
+ 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(c4 > 0) {
+ currentSize += (c2/UCOL_BOT_COUNT4)+1;
+ c4 = 0;
+ }
+ currentSize++;
+ if(primary2 != 0) {
+ currentSize++;
+ }
+ }
+ wasShifted = TRUE;
+ } else {
+ wasShifted = FALSE;
+ /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
+ /* Usually, we'll have non-zero primary1 & primary2, except in cases of a-z and friends, when primary2 will */
+ /* calculate sortkey size */
+ if(primary1 != UCOL_IGNORABLE) {
+ if(notIsContinuation) {
+ if(leadPrimary == primary1) {
+ currentSize++;
+ } else {
+ if(leadPrimary != 0) {
+ currentSize++;
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ currentSize++;
+ leadPrimary = 0;
+ } else if(isCompressible(coll, primary1)) {
+ /* compress */
+ leadPrimary = primary1;
+ currentSize+=2;
+ } else {
+ leadPrimary = 0;
+ currentSize+=2;
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ currentSize++;
+ if(primary2 != UCOL_IGNORABLE) {
+ currentSize++;
+ }
+ }
+ }
+
+ if(secondary > compareSec) { /* I think that != 0 test should be != IGNORABLE */
+ if(!isFrenchSec){
+ if (secondary == UCOL_COMMON2 && notIsContinuation) {
+ c2++;
+ } else {
+ if(c2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ currentSize += (c2/(uint32_t)UCOL_TOP_COUNT2)+1;
+ } else {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+1;
+ }
+ c2 = 0;
+ }
+ currentSize++;
+ }
+ } else {
+ fSecs[fSecsLen++] = secondary;
+ if(fSecsLen == fSecsMaxLen) {
+ uint8_t *fSecsTemp;
+ if(fSecs == fSecsBuff) {
+ fSecsTemp = (uint8_t *)uprv_malloc(2*fSecsLen);
+ } else {
+ fSecsTemp = (uint8_t *)uprv_realloc(fSecs, 2*fSecsLen);
+ }
+ if(fSecsTemp == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ fSecs = fSecsTemp;
+ fSecsMaxLen *= 2;
+ }
+ if(notIsContinuation) {
+ if (frenchStartPtr != NULL) {
+ /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ frenchStartPtr = NULL;
+ }
+ } else {
+ if (frenchStartPtr == NULL) {
+ frenchStartPtr = fSecs+fSecsLen-2;
+ }
+ frenchEndPtr = fSecs+fSecsLen-1;
+ }
+ }
+ }
+
+ if(doCase && (primary1 > 0 || strength >= UCOL_SECONDARY)) {
+ // do the case level if we need to do it. We don't want to calculate
+ // case level for primary ignorables if we have only primary strength and case level
+ // otherwise we would break well formedness of CEs
+ if (caseShift == 0) {
+ currentSize++;
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+ if((tertiary&0x3F) > 0 && notIsContinuation) {
+ caseShift--;
+ if((tertiary &0xC0) != 0) {
+ if (caseShift == 0) {
+ currentSize++;
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+ caseShift--;
+ }
+ }
+ } else {
+ if(notIsContinuation) {
+ tertiary ^= caseSwitch;
+ }
+ }
+
+ tertiary &= tertiaryMask;
+ if(tertiary > compareTer) { /* I think that != 0 test should be != IGNORABLE */
+ if (tertiary == tertiaryCommon && notIsContinuation) {
+ c3++;
+ } else {
+ if(c3 > 0) {
+ if((tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL)
+ || (tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST)) {
+ currentSize += (c3/(uint32_t)coll->tertiaryTopCount)+1;
+ } else {
+ currentSize += (c3/(uint32_t)coll->tertiaryBottomCount)+1;
+ }
+ c3 = 0;
+ }
+ currentSize++;
+ }
+ }
+
+ if(/*qShifted*/(compareQuad==0) && notIsContinuation) {
+ if(s->flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
+ if(c4>0) { // Close this part
+ currentSize += (c4/UCOL_BOT_COUNT4)+1;
+ c4 = 0;
+ }
+ currentSize++; // Add the Hiragana
+ } else { // This wasn't Hiragana, so we can continue adding stuff
+ c4++;
+ }
+ }
+ }
+ }
+
+ if(!isFrenchSec){
+ if(c2 > 0) {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+((c2%(uint32_t)UCOL_BOT_COUNT2 != 0)?1:0);
+ }
+ } else {
+ uint32_t i = 0;
+ if(frenchStartPtr != NULL) {
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ }
+ for(i = 0; i<fSecsLen; i++) {
+ secondary = *(fSecs+fSecsLen-i-1);
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2) {
+ ++c2;
+ } else {
+ if(c2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ currentSize += (c2/(uint32_t)UCOL_TOP_COUNT2)+((c2%(uint32_t)UCOL_TOP_COUNT2 != 0)?1:0);
+ } else {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+((c2%(uint32_t)UCOL_BOT_COUNT2 != 0)?1:0);
+ }
+ c2 = 0;
+ }
+ currentSize++;
+ }
+ }
+ if(c2 > 0) {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+((c2%(uint32_t)UCOL_BOT_COUNT2 != 0)?1:0);
+ }
+ if(fSecs != fSecsBuff) {
+ uprv_free(fSecs);
+ }
+ }
+
+ if(c3 > 0) {
+ currentSize += (c3/(uint32_t)coll->tertiaryBottomCount) + ((c3%(uint32_t)coll->tertiaryBottomCount != 0)?1:0);
+ }
+
+ if(c4 > 0 && compareQuad == 0) {
+ currentSize += (c4/(uint32_t)UCOL_BOT_COUNT4)+((c4%(uint32_t)UCOL_BOT_COUNT4 != 0)?1:0);
+ }
+
+ if(compareIdent) {
+ currentSize += u_lengthOfIdenticalLevelRun(s->string, len);
+ }
+ return currentSize;
+}
+
+static
+inline void doCaseShift(uint8_t **cases, uint32_t &caseShift) {
+ if (caseShift == 0) {
+ *(*cases)++ = UCOL_CASE_BYTE_START;
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+}
+
+// Adds a value to the buffer if it's safe to add. Increments the number of added values, so that we
+// know how many values we wanted to add, even if we didn't add them all
+static
+inline void addWithIncrement(uint8_t *&primaries, uint8_t *limit, uint32_t &size, const uint8_t value) {
+ size++;
+ if(primaries < limit) {
+ *(primaries)++ = value;
+ }
+}
+
+// Packs the secondary buffer when processing French locale. Adds the terminator.
+static
+inline uint8_t *packFrench(uint8_t *primaries, uint8_t *primEnd, uint8_t *secondaries, uint32_t *secsize, uint8_t *frenchStartPtr, uint8_t *frenchEndPtr) {
+ uint8_t secondary;
+ int32_t count2 = 0;
+ uint32_t i = 0, size = 0;
+ // we use i here since the key size already accounts for terminators, so we'll discard the increment
+ addWithIncrement(primaries, primEnd, i, UCOL_LEVELTERMINATOR);
+ /* If there are any unresolved continuation secondaries, reverse them here so that we can reverse the whole secondary thing */
+ if(frenchStartPtr != NULL) {
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ }
+ for(i = 0; i<*secsize; i++) {
+ secondary = *(secondaries-i-1);
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2) {
+ ++count2;
+ } else {
+ if (count2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ while (count2 > UCOL_TOP_COUNT2) {
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2));
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_TOP2 - (count2-1)));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ count2 = 0;
+ }
+ addWithIncrement(primaries, primEnd, size, secondary);
+ }
+ }
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ *secsize = size;
+ return primaries;
+}
+
+#define DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY 0
+
+/* This is the sortkey work horse function */
+U_CFUNC int32_t U_CALLCONV
+ucol_calcSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocateSKBuffer,
+ UErrorCode *status)
+{
+ //const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)coll->UCA->image + coll->image->UCAConsts);
+
+ uint32_t i = 0; /* general purpose counter */
+
+ /* Stack allocated buffers for buffers we use */
+ uint8_t prim[UCOL_PRIMARY_MAX_BUFFER], second[UCOL_SECONDARY_MAX_BUFFER], tert[UCOL_TERTIARY_MAX_BUFFER], caseB[UCOL_CASE_MAX_BUFFER], quad[UCOL_QUAD_MAX_BUFFER];
+
+ uint8_t *primaries = *result, *secondaries = second, *tertiaries = tert, *cases = caseB, *quads = quad;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(primaries == NULL && allocateSKBuffer == TRUE) {
+ primaries = *result = prim;
+ resultLength = UCOL_PRIMARY_MAX_BUFFER;
+ }
+
+ uint32_t secSize = UCOL_SECONDARY_MAX_BUFFER, terSize = UCOL_TERTIARY_MAX_BUFFER,
+ caseSize = UCOL_CASE_MAX_BUFFER, quadSize = UCOL_QUAD_MAX_BUFFER;
+
+ uint32_t sortKeySize = 1; /* it is always \0 terminated */
+
+ 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 */
+ uint8_t *frenchStartPtr = NULL;
+ uint8_t *frenchEndPtr = NULL;
+ uint32_t caseShift = 0;
+
+ sortKeySize += ((compareSec?0:1) + (compareTer?0:1) + (doCase?1:0) + /*(qShifted?1:0)*/(compareQuad?0:1) + (compareIdent?1:0));
+
+ /* If we need to normalize, we'll do it all at once at the beginning! */
+ 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 0;
+ }
+ s.flags &= ~UCOL_ITER_NORM; // source passed the FCD test or else was normalized.
+
+ if(resultLength == 0 || primaries == NULL) {
+ return ucol_getSortKeySize(coll, &s, sortKeySize, strength, len);
+ }
+ uint8_t *primarySafeEnd = primaries + resultLength - 1;
+ if(strength > UCOL_PRIMARY) {
+ primarySafeEnd--;
+ }
+
+ uint32_t minBufferSize = UCOL_MAX_BUFFER;
+
+ uint8_t *primStart = primaries;
+ uint8_t *secStart = secondaries;
+ uint8_t *terStart = tertiaries;
+ uint8_t *caseStart = cases;
+ uint8_t *quadStart = quads;
+
+ uint32_t order = 0;
+
+ uint8_t primary1 = 0;
+ uint8_t primary2 = 0;
+ uint8_t secondary = 0;
+ uint8_t tertiary = 0;
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+ int8_t tertiaryAddition = coll->tertiaryAddition;
+ uint8_t tertiaryTop = coll->tertiaryTop;
+ uint8_t tertiaryBottom = coll->tertiaryBottom;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+ uint8_t caseBits = 0;
+
+ UBool finished = FALSE;
+ UBool wasShifted = FALSE;
+ UBool notIsContinuation = FALSE;
+
+ uint32_t prevBuffSize = 0;
+
+ uint32_t count2 = 0, count3 = 0, count4 = 0;
+ uint8_t leadPrimary = 0;
+
+ for(;;) {
+ for(i=prevBuffSize; i<minBufferSize; ++i) {
+
+ order = ucol_IGetNextCE(coll, &s, status);
+ if(order == UCOL_NO_MORE_CES) {
+ finished = TRUE;
+ break;
+ }
+
+ if(order == 0) {
+ continue;
+ }
+
+ notIsContinuation = !isContinuation(order);
+
+ if(notIsContinuation) {
+ tertiary = (uint8_t)(order & UCOL_BYTE_SIZE_MASK);
+ } else {
+ tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
+ }
+
+ secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(order >> 8);
+
+ 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++ = (uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + (count4-1));
+ count4 = 0;
+ }
+ /* We are dealing with a variable and we're treating them as shifted */
+ /* This is a shifted ignorable */
+ if(primary1 != 0) { /* we need to check this since we could be in continuation */
+ *quads++ = primary1;
+ }
+ if(primary2 != 0) {
+ *quads++ = primary2;
+ }
+ }
+ wasShifted = TRUE;
+ } else {
+ wasShifted = FALSE;
+ /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
+ /* Usually, we'll have non-zero primary1 & primary2, except in cases of a-z and friends, when primary2 will */
+ /* regular and simple sortkey calc */
+ if(primary1 != UCOL_IGNORABLE) {
+ if(notIsContinuation) {
+ if(leadPrimary == primary1) {
+ *primaries++ = primary2;
+ } else {
+ if(leadPrimary != 0) {
+ *primaries++ = (uint8_t)((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN);
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ *primaries++ = primary1;
+ leadPrimary = 0;
+ } else if(isCompressible(coll, originalPrimary1)) {
+ /* compress */
+ *primaries++ = leadPrimary = primary1;
+ if(primaries <= primarySafeEnd) {
+ *primaries++ = primary2;
+ }
+ } else {
+ leadPrimary = 0;
+ *primaries++ = primary1;
+ if(primaries <= primarySafeEnd) {
+ *primaries++ = primary2;
+ }
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ *primaries++ = primary1;
+ if((primary2 != UCOL_IGNORABLE) && (primaries <= primarySafeEnd)) {
+ *primaries++ = primary2; /* second part */
+ }
+ }
+ }
+
+ if(secondary > compareSec) {
+ if(!isFrenchSec) {
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2 && notIsContinuation) {
+ ++count2;
+ } else {
+ if (count2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ while (count2 > UCOL_TOP_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - (count2-1));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ count2 = 0;
+ }
+ *secondaries++ = secondary;
+ }
+ } else {
+ *secondaries++ = secondary;
+ /* Do the special handling for French secondaries */
+ /* We need to get continuation elements and do intermediate restore */
+ /* abc1c2c3de with french secondaries need to be edc1c2c3ba NOT edc3c2c1ba */
+ if(notIsContinuation) {
+ if (frenchStartPtr != NULL) {
+ /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ frenchStartPtr = NULL;
+ }
+ } else {
+ if (frenchStartPtr == NULL) {
+ frenchStartPtr = secondaries - 2;
+ }
+ frenchEndPtr = secondaries-1;
+ }
+ }
+ }
+
+ if(doCase && (primary1 > 0 || strength >= UCOL_SECONDARY)) {
+ // do the case level if we need to do it. We don't want to calculate
+ // case level for primary ignorables if we have only primary strength and case level
+ // otherwise we would break well formedness of CEs
+ doCaseShift(&cases, caseShift);
+ if(notIsContinuation) {
+ caseBits = (uint8_t)(tertiary & 0xC0);
+
+ if(tertiary != 0) {
+ if(coll->caseFirst == UCOL_UPPER_FIRST) {
+ if((caseBits & 0xC0) == 0) {
+ *(cases-1) |= 1 << (--caseShift);
+ } else {
+ *(cases-1) |= 0 << (--caseShift);
+ /* second bit */
+ doCaseShift(&cases, caseShift);
+ *(cases-1) |= ((caseBits>>6)&1) << (--caseShift);
+ }
+ } else {
+ if((caseBits & 0xC0) == 0) {
+ *(cases-1) |= 0 << (--caseShift);
+ } else {
+ *(cases-1) |= 1 << (--caseShift);
+ /* second bit */
+ doCaseShift(&cases, caseShift);
+ *(cases-1) |= ((caseBits>>7)&1) << (--caseShift);
+ }
+ }
+ }
+
+ }
+ } else {
+ if(notIsContinuation) {
+ tertiary ^= caseSwitch;
+ }
+ }
+
+ tertiary &= tertiaryMask;
+ if(tertiary > compareTer) {
+ /* This is compression code. */
+ /* sequence size check is included in the if clause */
+ if (tertiary == tertiaryCommon && notIsContinuation) {
+ ++count3;
+ } else {
+ if(tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL) {
+ tertiary += tertiaryAddition;
+ } else if(tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST) {
+ tertiary -= tertiaryAddition;
+ }
+ if (count3 > 0) {
+ if ((tertiary > tertiaryCommon)) {
+ while (count3 > coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - (count3-1));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ count3 = 0;
+ }
+ *tertiaries++ = tertiary;
+ }
+ }
+
+ if(/*qShifted*/(compareQuad==0) && notIsContinuation) {
+ if(s.flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
+ if(count4>0) { // Close this part
+ while (count4 > UCOL_BOT_COUNT4) {
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + (count4-1));
+ count4 = 0;
+ }
+ *quads++ = UCOL_HIRAGANA_QUAD; // Add the Hiragana
+ } else { // This wasn't Hiragana, so we can continue adding stuff
+ count4++;
+ }
+ }
+ }
+
+ if(primaries > primarySafeEnd) { /* We have stepped over the primary buffer */
+ if(allocateSKBuffer == FALSE) { /* need to save our butts if we cannot reallocate */
+ IInit_collIterate(coll, (UChar *)source, len, &s, status);
+ if(U_FAILURE(*status)) {
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ finished = TRUE;
+ break;
+ }
+ s.flags &= ~UCOL_ITER_NORM;
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, strength, len);
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ finished = TRUE;
+ break;
+ } else { /* It's much nicer if we can actually reallocate */
+ int32_t sks = sortKeySize+(int32_t)((primaries - primStart)+(secondaries - secStart)+(tertiaries - terStart)+(cases-caseStart)+(quads-quadStart));
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sks, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ primarySafeEnd = primStart + resultLength - 1;
+ if(strength > UCOL_PRIMARY) {
+ primarySafeEnd--;
+ }
+ } else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ finished = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if(finished) {
+ break;
+ } else {
+ prevBuffSize = minBufferSize;
+
+ uint32_t frenchStartOffset = 0, frenchEndOffset = 0;
+ if (frenchStartPtr != NULL) {
+ frenchStartOffset = (uint32_t)(frenchStartPtr - secStart);
+ frenchEndOffset = (uint32_t)(frenchEndPtr - secStart);
+ }
+ secStart = reallocateBuffer(&secondaries, secStart, second, &secSize, 2*secSize, status);
+ terStart = reallocateBuffer(&tertiaries, terStart, tert, &terSize, 2*terSize, status);
+ caseStart = reallocateBuffer(&cases, caseStart, caseB, &caseSize, 2*caseSize, status);
+ quadStart = reallocateBuffer(&quads, quadStart, quad, &quadSize, 2*quadSize, status);
+ if(U_FAILURE(*status)) {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ break;
+ }
+ if (frenchStartPtr != NULL) {
+ frenchStartPtr = secStart + frenchStartOffset;
+ frenchEndPtr = secStart + frenchEndOffset;
+ }
+ minBufferSize *= 2;
+ }
+ }
+
+ /* Here, we are generally done with processing */
+ /* bailing out would not be too productive */
+
+ if(U_SUCCESS(*status)) {
+ sortKeySize += (uint32_t)(primaries - primStart);
+ /* we have done all the CE's, now let's put them together to form a key */
+ if(compareSec == 0) {
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ uint32_t secsize = (uint32_t)(secondaries-secStart);
+ if(!isFrenchSec) { // Regular situation, we know the length of secondaries
+ sortKeySize += secsize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, secStart, secsize);
+ primaries += secsize;
+ } else {
+ if(allocateSKBuffer == TRUE) { /* need to save our butts if we cannot reallocate */
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, secStart, secsize);
+ primaries += secsize;
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ } else { // French secondary is on. We will need to pack French. packFrench will add the level terminator
+ uint8_t *newPrim = packFrench(primaries, primStart+resultLength, secondaries, &secsize, frenchStartPtr, frenchEndPtr);
+ sortKeySize += secsize;
+ if(sortKeySize <= resultLength) { // if we managed to pack fine
+ primaries = newPrim; // update the primary pointer
+ } else { // overflow, need to reallocate and redo
+ if(allocateSKBuffer == TRUE) { /* need to save our butts if we cannot reallocate */
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ primaries = packFrench(primaries, primStart+resultLength, secondaries, &secsize, frenchStartPtr, frenchEndPtr);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+ }
+
+ if(doCase) {
+ uint32_t casesize = (uint32_t)(cases - caseStart);
+ sortKeySize += casesize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, caseStart, casesize);
+ primaries += casesize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, caseStart, casesize);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+
+ if(compareTer == 0) {
+ if (count3 > 0) {
+ if (coll->tertiaryCommon != UCOL_COMMON_BOT3) {
+ while (count3 >= coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - count3);
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ }
+ uint32_t tersize = (uint32_t)(tertiaries - terStart);
+ sortKeySize += tersize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ primaries += tersize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+
+ if(compareQuad == 0/*qShifted == TRUE*/) {
+ if(count4 > 0) {
+ while (count4 > UCOL_BOT_COUNT4) {
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + (count4-1));
+ }
+ uint32_t quadsize = (uint32_t)(quads - quadStart);
+ sortKeySize += quadsize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, quadStart, quadsize);
+ primaries += quadsize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, quadStart, quadsize);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+
+ if(compareIdent) {
+ sortKeySize += u_lengthOfIdenticalLevelRun(s.string, len);
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ primaries += u_writeIdenticalLevelRun(s.string, len, primaries);
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ u_writeIdenticalLevelRun(s.string, len, primaries);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+ }
+ *(primaries++) = '\0';
+ }
+
+ if(allocateSKBuffer == TRUE) {
+ *result = (uint8_t*)uprv_malloc(sortKeySize);
+ /* test for NULL */
+ if (*result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ uprv_memcpy(*result, primStart, sortKeySize);
+ if(primStart != prim) {
+ uprv_free(primStart);
+ }
+ }
+
+cleanup:
+ if (allocateSKBuffer == FALSE && resultLength > 0 && U_FAILURE(*status) && *status != U_BUFFER_OVERFLOW_ERROR) {
+ /* NULL terminate for safety */
+ **result = 0;
+ }
+ if(terStart != tert) {
+ uprv_free(terStart);
+ uprv_free(secStart);
+ uprv_free(caseStart);
+ uprv_free(quadStart);
+ }
+
+ /* To avoid memory leak, free the offset buffer if necessary. */
+ ucol_freeOffsetBuffer(&s);
+
+ return sortKeySize;
+}
+
+
+U_CFUNC int32_t U_CALLCONV
+ucol_calcSortKeySimpleTertiary(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocateSKBuffer,
+ UErrorCode *status)
+{
+ U_ALIGN_CODE(16);
+
+ //const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)coll->UCA->image + coll->image->UCAConsts);
+ uint32_t i = 0; /* general purpose counter */
+
+ /* Stack allocated buffers for buffers we use */
+ uint8_t prim[UCOL_PRIMARY_MAX_BUFFER], second[UCOL_SECONDARY_MAX_BUFFER], tert[UCOL_TERTIARY_MAX_BUFFER];
+
+ uint8_t *primaries = *result, *secondaries = second, *tertiaries = tert;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(primaries == NULL && allocateSKBuffer == TRUE) {
+ primaries = *result = prim;
+ resultLength = UCOL_PRIMARY_MAX_BUFFER;
+ }
+
+ uint32_t secSize = UCOL_SECONDARY_MAX_BUFFER, terSize = UCOL_TERTIARY_MAX_BUFFER;
+
+ uint32_t sortKeySize = 3; /* it is always \0 terminated plus separators for secondary and tertiary */
+
+ 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 0;
+ }
+ s.flags &= ~UCOL_ITER_NORM; // source passed the FCD test or else was normalized.
+
+ if(resultLength == 0 || primaries == NULL) {
+ return ucol_getSortKeySize(coll, &s, sortKeySize, coll->strength, len);
+ }
+
+ uint8_t *primarySafeEnd = primaries + resultLength - 2;
+
+ uint32_t minBufferSize = UCOL_MAX_BUFFER;
+
+ uint8_t *primStart = primaries;
+ uint8_t *secStart = secondaries;
+ uint8_t *terStart = tertiaries;
+
+ uint32_t order = 0;
+
+ uint8_t primary1 = 0;
+ uint8_t primary2 = 0;
+ uint8_t secondary = 0;
+ uint8_t tertiary = 0;
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+ int8_t tertiaryAddition = coll->tertiaryAddition;
+ uint8_t tertiaryTop = coll->tertiaryTop;
+ uint8_t tertiaryBottom = coll->tertiaryBottom;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+
+ uint32_t prevBuffSize = 0;
+
+ UBool finished = FALSE;
+ UBool notIsContinuation = FALSE;
+
+ uint32_t count2 = 0, count3 = 0;
+ uint8_t leadPrimary = 0;
+
+ for(;;) {
+ for(i=prevBuffSize; i<minBufferSize; ++i) {
+
+ order = ucol_IGetNextCE(coll, &s, status);
+
+ if(order == 0) {
+ continue;
+ }
+
+ if(order == UCOL_NO_MORE_CES) {
+ finished = TRUE;
+ break;
+ }
+
+ notIsContinuation = !isContinuation(order);
+
+ if(notIsContinuation) {
+ tertiary = (uint8_t)((order & tertiaryMask));
+ } else {
+ tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
+ }
+
+ secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(order >> 8);
+
+ 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++ = primary2;
+ } else {
+ if(leadPrimary != 0) {
+ *primaries++ = (uint8_t)((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN);
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ *primaries++ = primary1;
+ leadPrimary = 0;
+ } else if(isCompressible(coll, originalPrimary1)) {
+ /* compress */
+ *primaries++ = leadPrimary = primary1;
+ *primaries++ = primary2;
+ } else {
+ leadPrimary = 0;
+ *primaries++ = primary1;
+ *primaries++ = primary2;
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ *primaries++ = primary1;
+ if(primary2 != UCOL_IGNORABLE) {
+ *primaries++ = primary2; /* second part */
+ }
+ }
+ }
+
+ if(secondary > 0) { /* I think that != 0 test should be != IGNORABLE */
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2 && notIsContinuation) {
+ ++count2;
+ } else {
+ if (count2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ while (count2 > UCOL_TOP_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - (count2-1));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ count2 = 0;
+ }
+ *secondaries++ = secondary;
+ }
+ }
+
+ if(notIsContinuation) {
+ tertiary ^= caseSwitch;
+ }
+
+ if(tertiary > 0) {
+ /* This is compression code. */
+ /* sequence size check is included in the if clause */
+ if (tertiary == tertiaryCommon && notIsContinuation) {
+ ++count3;
+ } else {
+ if(tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL) {
+ tertiary += tertiaryAddition;
+ } else if (tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST) {
+ tertiary -= tertiaryAddition;
+ }
+ if (count3 > 0) {
+ if ((tertiary > tertiaryCommon)) {
+ while (count3 > coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - (count3-1));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ count3 = 0;
+ }
+ *tertiaries++ = tertiary;
+ }
+ }
+
+ if(primaries > primarySafeEnd) { /* We have stepped over the primary buffer */
+ if(allocateSKBuffer == FALSE) { /* need to save our butts if we cannot reallocate */
+ IInit_collIterate(coll, (UChar *)source, len, &s, status);
+ if(U_FAILURE(*status)) {
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ finished = TRUE;
+ break;
+ }
+ s.flags &= ~UCOL_ITER_NORM;
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, coll->strength, len);
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ finished = TRUE;
+ break;
+ } else { /* It's much nicer if we can actually reallocate */
+ int32_t sks = sortKeySize+(int32_t)((primaries - primStart)+(secondaries - secStart)+(tertiaries - terStart));
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sks, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ primarySafeEnd = primStart + resultLength - 2;
+ } else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ finished = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if(finished) {
+ break;
+ } else {
+ prevBuffSize = minBufferSize;
+ secStart = reallocateBuffer(&secondaries, secStart, second, &secSize, 2*secSize, status);
+ terStart = reallocateBuffer(&tertiaries, terStart, tert, &terSize, 2*terSize, status);
+ minBufferSize *= 2;
+ if(U_FAILURE(*status)) { // if we cannot reallocate buffers, we can at least give the sortkey size
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ break;
+ }
+ }
+ }
+
+ if(U_SUCCESS(*status)) {
+ sortKeySize += (uint32_t)(primaries - primStart);
+ /* we have done all the CE's, now let's put them together to form a key */
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ uint32_t secsize = (uint32_t)(secondaries-secStart);
+ sortKeySize += secsize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, secStart, secsize);
+ primaries += secsize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ *result = primStart;
+ uprv_memcpy(primaries, secStart, secsize);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+
+ if (count3 > 0) {
+ if (coll->tertiaryCommon != UCOL_COMMON3_NORMAL) {
+ while (count3 >= coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - count3);
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ }
+ uint32_t tersize = (uint32_t)(tertiaries - terStart);
+ sortKeySize += tersize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ primaries += tersize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ }
+ else {
+ /* We ran out of memory!? We can't recover. */
+ sortKeySize = DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY;
+ goto cleanup;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+
+ *(primaries++) = '\0';
+ }
+
+ if(allocateSKBuffer == TRUE) {
+ *result = (uint8_t*)uprv_malloc(sortKeySize);
+ /* test for NULL */
+ if (*result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ uprv_memcpy(*result, primStart, sortKeySize);
+ if(primStart != prim) {
+ uprv_free(primStart);
+ }
+ }
+
+cleanup:
+ if (allocateSKBuffer == FALSE && resultLength > 0 && U_FAILURE(*status) && *status != U_BUFFER_OVERFLOW_ERROR) {
+ /* NULL terminate for safety */
+ **result = 0;
+ }
+ if(terStart != tert) {
+ uprv_free(terStart);
+ uprv_free(secStart);
+ }
+
+ /* To avoid memory leak, free the offset buffer if necessary. */
+ ucol_freeOffsetBuffer(&s);
+
+ return sortKeySize;
+}
+
+static inline
+UBool isShiftedCE(uint32_t CE, uint32_t LVT, UBool *wasShifted) {
+ UBool notIsContinuation = !isContinuation(CE);
+ uint8_t primary1 = (uint8_t)((CE >> 24) & 0xFF);
+ if((LVT && ((notIsContinuation && (CE & 0xFFFF0000)<= LVT && primary1 > 0)
+ || (!notIsContinuation && *wasShifted)))
+ || (*wasShifted && primary1 == 0)) /* amendment to the UCA says that primary ignorables */
+ {
+ // The stuff below should probably be in the sortkey code... maybe not...
+ if(primary1 != 0) { /* if we were shifted and we got an ignorable code point */
+ /* we should just completely ignore it */
+ *wasShifted = TRUE;
+ //continue;
+ }
+ //*wasShifted = TRUE;
+ return TRUE;
+ } else {
+ *wasShifted = FALSE;
+ return FALSE;
+ }
+}
+static inline
+void terminatePSKLevel(int32_t level, int32_t maxLevel, int32_t &i, uint8_t *dest) {
+ if(level < maxLevel) {
+ dest[i++] = UCOL_LEVELTERMINATOR;
+ } else {
+ dest[i++] = 0;
+ }
+}
+
+/** enumeration of level identifiers for partial sort key generation */
+enum {
+ UCOL_PSK_PRIMARY = 0,
+ UCOL_PSK_SECONDARY = 1,
+ UCOL_PSK_CASE = 2,
+ UCOL_PSK_TERTIARY = 3,
+ UCOL_PSK_QUATERNARY = 4,
+ UCOL_PSK_QUIN = 5, /** This is an extra level, not used - but we have three bits to blow */
+ UCOL_PSK_IDENTICAL = 6,
+ UCOL_PSK_NULL = 7, /** level for the end of sort key. Will just produce zeros */
+ UCOL_PSK_LIMIT
+};
+
+/** collation state enum. *_SHIFT value is how much to shift right
+ * to get the state piece to the right. *_MASK value should be
+ * ANDed with the shifted state. This data is stored in state[1]
+ * field.
+ */
+enum {
+ UCOL_PSK_LEVEL_SHIFT = 0, /** level identificator. stores an enum value from above */
+ UCOL_PSK_LEVEL_MASK = 7, /** three bits */
+ UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT = 3, /** number of bytes of primary or quaternary already written */
+ UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK = 1,
+ /** can be only 0 or 1, since we get up to two bytes from primary or quaternary
+ * This field is also used to denote that the French secondary level is finished
+ */
+ UCOL_PSK_WAS_SHIFTED_SHIFT = 4,/** was the last value shifted */
+ UCOL_PSK_WAS_SHIFTED_MASK = 1, /** can be 0 or 1 (Boolean) */
+ UCOL_PSK_USED_FRENCH_SHIFT = 5,/** how many French bytes have we already written */
+ UCOL_PSK_USED_FRENCH_MASK = 3, /** up to 4 bytes. See comment just below */
+ /** When we do French we need to reverse secondary values. However, continuations
+ * need to stay the same. So if you had abc1c2c3de, you need to have edc1c2c3ba
+ */
+ UCOL_PSK_BOCSU_BYTES_SHIFT = 7,
+ UCOL_PSK_BOCSU_BYTES_MASK = 3,
+ UCOL_PSK_CONSUMED_CES_SHIFT = 9,
+ UCOL_PSK_CONSUMED_CES_MASK = 0x7FFFF
+};
+
+// macro calculating the number of expansion CEs available
+#define uprv_numAvailableExpCEs(s) (s).CEpos - (s).toReturn
+
+
+/** main sortkey part procedure. On the first call,
+ * you should pass in a collator, an iterator, empty state
+ * state[0] == state[1] == 0, a buffer to hold results
+ * number of bytes you need and an error code pointer.
+ * Make sure your buffer is big enough to hold the wanted
+ * number of sortkey bytes. I don't check.
+ * The only meaningful status you can get back is
+ * U_BUFFER_OVERFLOW_ERROR, which basically means that you
+ * have been dealt a raw deal and that you probably won't
+ * be able to use partial sortkey generation for this
+ * particular combination of string and collator. This
+ * is highly unlikely, but you should still check the error code.
+ * Any other status means that you're not in a sane situation
+ * anymore. After the first call, preserve state values and
+ * use them on subsequent calls to obtain more bytes of a sortkey.
+ * Use until the number of bytes written is smaller than the requested
+ * number of bytes. Generated sortkey is not compatible with the
+ * one generated by ucol_getSortKey, as we don't do any compression.
+ * However, levels are still terminated by a 1 (one) and the sortkey
+ * is terminated by a 0 (zero). Identical level is the same as in the
+ * regular sortkey - internal bocu-1 implementation is used.
+ * For curious, although you cannot do much about this, here is
+ * the structure of state words.
+ * state[0] - iterator state. Depends on the iterator implementation,
+ * but allows the iterator to continue where it stopped in
+ * the last iteration.
+ * state[1] - collation processing state. Here is the distribution
+ * of the bits:
+ * 0, 1, 2 - level of the sortkey - primary, secondary, case, tertiary
+ * quaternary, quin (we don't use this one), identical and
+ * null (producing only zeroes - first one to terminate the
+ * sortkey and subsequent to fill the buffer).
+ * 3 - byte count. Number of bytes written on the primary level.
+ * 4 - was shifted. Whether the previous iteration finished in the
+ * shifted state.
+ * 5, 6 - French continuation bytes written. See the comment in the enum
+ * 7,8 - Bocsu bytes used. Number of bytes from a bocu sequence on
+ * the identical level.
+ * 9..31 - CEs consumed. Number of getCE or next32 operations performed
+ * since thes last successful update of the iterator state.
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_nextSortKeyPart(const UCollator *coll,
+ UCharIterator *iter,
+ uint32_t state[2],
+ uint8_t *dest, int32_t count,
+ UErrorCode *status)
+{
+ /* error checking */
+ if(status==NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+ UTRACE_ENTRY(UTRACE_UCOL_NEXTSORTKEYPART);
+ if( coll==NULL || iter==NULL ||
+ state==NULL ||
+ count<0 || (count>0 && dest==NULL)
+ ) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ UTRACE_EXIT_STATUS(status);
+ return 0;
+ }
+
+ UTRACE_DATA6(UTRACE_VERBOSE, "coll=%p, iter=%p, state=%d %d, dest=%p, count=%d",
+ coll, iter, state[0], state[1], dest, count);
+
+ if(count==0) {
+ /* nothing to do */
+ UTRACE_EXIT_VALUE(0);
+ return 0;
+ }
+ /** Setting up situation according to the state we got from the previous iteration */
+ // The state of the iterator from the previous invocation
+ uint32_t iterState = state[0];
+ // Has the last iteration ended in the shifted state
+ UBool wasShifted = ((state[1] >> UCOL_PSK_WAS_SHIFTED_SHIFT) & UCOL_PSK_WAS_SHIFTED_MASK)?TRUE:FALSE;
+ // What is the current level of the sortkey?
+ int32_t level= (state[1] >> UCOL_PSK_LEVEL_SHIFT) & UCOL_PSK_LEVEL_MASK;
+ // Have we written only one byte from a two byte primary in the previous iteration?
+ // Also on secondary level - have we finished with the French secondary?
+ int32_t byteCountOrFrenchDone = (state[1] >> UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK;
+ // number of bytes in the continuation buffer for French
+ int32_t usedFrench = (state[1] >> UCOL_PSK_USED_FRENCH_SHIFT) & UCOL_PSK_USED_FRENCH_MASK;
+ // Number of bytes already written from a bocsu sequence. Since
+ // the longes bocsu sequence is 4 long, this can be up to 3.
+ int32_t bocsuBytesUsed = (state[1] >> UCOL_PSK_BOCSU_BYTES_SHIFT) & UCOL_PSK_BOCSU_BYTES_MASK;
+ // Number of elements that need to be consumed in this iteration because
+ // the iterator returned UITER_NO_STATE at the end of the last iteration,
+ // so we had to save the last valid state.
+ int32_t cces = (state[1] >> UCOL_PSK_CONSUMED_CES_SHIFT) & UCOL_PSK_CONSUMED_CES_MASK;
+
+ /** values that depend on the collator attributes */
+ // strength of the collator.
+ int32_t strength = ucol_getAttribute(coll, UCOL_STRENGTH, status);
+ // maximal level of the partial sortkey. Need to take whether case level is done
+ int32_t maxLevel = 0;
+ if(strength < UCOL_TERTIARY) {
+ if(ucol_getAttribute(coll, UCOL_CASE_LEVEL, status) == UCOL_ON) {
+ maxLevel = UCOL_PSK_CASE;
+ } else {
+ maxLevel = strength;
+ }
+ } else {
+ if(strength == UCOL_TERTIARY) {
+ maxLevel = UCOL_PSK_TERTIARY;
+ } else if(strength == UCOL_QUATERNARY) {
+ maxLevel = UCOL_PSK_QUATERNARY;
+ } else { // identical
+ maxLevel = UCOL_IDENTICAL;
+ }
+ }
+ // value for the quaternary level if Hiragana is encountered. Used for JIS X 4061 collation
+ uint8_t UCOL_HIRAGANA_QUAD =
+ (ucol_getAttribute(coll, UCOL_HIRAGANA_QUATERNARY_MODE, status) == UCOL_ON)?0xFE:0xFF;
+ // Boundary value that decides whether a CE is shifted or not
+ uint32_t LVT = (coll->alternateHandling == UCOL_SHIFTED)?(coll->variableTopValue<<16):0;
+ // Are we doing French collation?
+ UBool doingFrench = (ucol_getAttribute(coll, UCOL_FRENCH_COLLATION, status) == UCOL_ON);
+
+ /** initializing the collation state */
+ UBool notIsContinuation = FALSE;
+ uint32_t CE = UCOL_NO_MORE_CES;
+
+ collIterate s;
+ IInit_collIterate(coll, NULL, -1, &s, 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 - UCOL_COMMON_BOT3-1);
+ coll->tertiaryTopCount = (uint8_t)(UCOL_PROPORTION3*tertiaryTotal); /* we multilply double with int, but need only int */
+ coll->tertiaryBottomCount = (uint8_t)(tertiaryTotal - coll->tertiaryTopCount);
+
+ if(coll->caseLevel == UCOL_OFF && coll->strength == UCOL_TERTIARY
+ && coll->frenchCollation == UCOL_OFF && coll->alternateHandling == UCOL_NON_IGNORABLE)
+ {
+ coll->sortKeyGen = ucol_calcSortKeySimpleTertiary;
+ } else {
+ coll->sortKeyGen = ucol_calcSortKey;
+ }
+ if(coll->caseLevel == UCOL_OFF && coll->strength <= UCOL_TERTIARY && coll->numericCollation == UCOL_OFF
+ && coll->alternateHandling == UCOL_NON_IGNORABLE && !coll->latinOneFailed)
+ {
+ if(coll->latinOneCEs == NULL || coll->latinOneRegenTable) {
+ if(ucol_setUpLatinOne(coll, status)) { // if we succeed in building latin1 table, we'll use it
+ //fprintf(stderr, "F");
+ coll->latinOneUse = TRUE;
+ } else {
+ coll->latinOneUse = FALSE;
+ }
+ if(*status == U_UNSUPPORTED_ERROR) {
+ *status = U_ZERO_ERROR;
+ }
+ } else { // latin1Table exists and it doesn't need to be regenerated, just use it
+ coll->latinOneUse = TRUE;
+ }
+ } else {
+ coll->latinOneUse = FALSE;
+ }
+ }
+}
+
+U_CAPI uint32_t U_EXPORT2
+ucol_setVariableTop(UCollator *coll, const UChar *varTop, int32_t len, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL) {
+ return 0;
+ }
+ if(len == -1) {
+ len = u_strlen(varTop);
+ }
+ if(len == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ collIterate s;
+ IInit_collIterate(coll, varTop, len, &s, 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_INTERNAL int32_t U_EXPORT2
+ucol_getReorderCodes(const UCollator *coll,
+ int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+
+ if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if (coll->reorderCodesLength > destCapacity) {
+ *pErrorCode = 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_INTERNAL void U_EXPORT2
+ucol_setReorderCodes(UCollator *coll,
+ const int32_t *reorderCodes,
+ int32_t reorderCodesLength,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return;
+ }
+
+ if (reorderCodesLength < 0 || (reorderCodesLength > 0 && reorderCodes == NULL)) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ uprv_free(coll->reorderCodes);
+ coll->reorderCodes = NULL;
+ coll->reorderCodesLength = 0;
+ if (reorderCodesLength == 0) {
+ uprv_free(coll->leadBytePermutationTable);
+ coll->leadBytePermutationTable = NULL;
+ return;
+ }
+ coll->reorderCodes = (int32_t*) uprv_malloc(reorderCodesLength * sizeof(int32_t));
+ if (coll->reorderCodes == NULL) {
+ *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (int32_t i = 0; i < reorderCodesLength; i++) {
+ coll->reorderCodes[i] = reorderCodes[i];
+ }
+ coll->reorderCodesLength = reorderCodesLength;
+ ucol_buildPermutationTable(coll, pErrorCode);
+ if (U_FAILURE(*pErrorCode)) {
+ uprv_free(coll->reorderCodes);
+ coll->reorderCodes = NULL;
+ coll->reorderCodesLength = 0;
+ }
+}
+
+
+/****************************************************************************/
+/* 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.6/i18n/ucol_bld.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_bld.cpp
new file mode 100644
index 00000000000..1de473affbe
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_bld.cpp
@@ -0,0 +1,1417 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2010, 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"
+
+U_NAMESPACE_BEGIN
+
+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;
+}
+
+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_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;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/ucol_bld.h b/Build/source/libs/icu/icu-4.6/i18n/ucol_bld.h
new file mode 100644
index 00000000000..e722c6cc79d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucol_cnt.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_cnt.cpp
new file mode 100644
index 00000000000..7c274b763e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucol_cnt.h b/Build/source/libs/icu/icu-4.6/i18n/ucol_cnt.h
new file mode 100644
index 00000000000..f6dfcd77b26
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucol_elm.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_elm.cpp
new file mode 100644
index 00000000000..bb686eed6f3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucol_elm.h b/Build/source/libs/icu/icu-4.6/i18n/ucol_elm.h
new file mode 100644
index 00000000000..9c85b197f17
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucol_imp.h b/Build/source/libs/icu/icu-4.6/i18n/ucol_imp.h
new file mode 100644
index 00000000000..6604bab6648
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_imp.h
@@ -0,0 +1,1133 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1998-2010, 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 ((uint8_t)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
+#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
+
+#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);
+/* function used by C++ getCollationKey to prevent restarting the calculation */
+U_CFUNC int32_t
+ucol_getSortKeyWithAllocation(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ uint8_t **pResult,
+ UErrorCode *pErrorCode);
+
+/* get some memory */
+void *ucol_getABuffer(const UCollator *coll, uint32_t size);
+
+/* worker function for generating sortkeys */
+U_CFUNC
+int32_t U_CALLCONV
+ucol_calcSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocatePrimary,
+ UErrorCode *status);
+
+U_CFUNC
+int32_t U_CALLCONV
+ucol_calcSortKeySimpleTertiary(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocatePrimary,
+ UErrorCode *status);
+
+U_CFUNC
+int32_t
+ucol_getSortKeySize(const UCollator *coll, U_NAMESPACE_QUALIFIER collIterate *s,
+ int32_t currentSize, UColAttributeValue strength,
+ int32_t len);
+/**
+ * Makes a copy of the Collator's rule data. The format is
+ * that of .col files.
+ *
+ * @param length returns the length of the data, in bytes.
+ * @param status the error status
+ * @return memory, owned by the caller, of size 'length' bytes.
+ * @internal INTERNAL USE ONLY
+ */
+U_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 int32_t U_CALLCONV
+SortKeyGenerator(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocatePrimary,
+ UErrorCode *status);
+
+typedef void U_CALLCONV
+ResourceCleaner(UCollator *coll);
+
+
+struct UCollator {
+ UColOptionSet *options;
+ SortKeyGenerator *sortKeyGen;
+ uint32_t *latinOneCEs;
+ char* 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 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* 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_CAPI void U_EXPORT2 ucol_buildPermutationTable(UCollator *coll, UErrorCode *status);
+
+
+#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.6/i18n/ucol_res.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_res.cpp
new file mode 100644
index 00000000000..f96a55784bf
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_res.cpp
@@ -0,0 +1,1295 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2010, 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 &&
+ pInfo->formatVersion[1]>=UCA_FORMAT_VERSION_1// &&
+ //pInfo->formatVersion[1]==UCA_FORMAT_VERSION_1 &&
+ //pInfo->formatVersion[2]==UCA_FORMAT_VERSION_2 && // Too harsh
+ //pInfo->formatVersion[3]==UCA_FORMAT_VERSION_3 && // Too harsh
+ ) {
+ UVersionInfo UCDVersion;
+ u_getUnicodeVersion(UCDVersion);
+ return (UBool)(pInfo->dataVersion[0]==UCDVersion[0]
+ && pInfo->dataVersion[1]==UCDVersion[1]);
+ //&& pInfo->dataVersion[2]==ucaDataInfo.dataVersion[2]
+ //&& pInfo->dataVersion[3]==ucaDataInfo.dataVersion[3]);
+ } else {
+ return FALSE;
+ }
+}
+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);
+ ucol_setReorderCodes(result, reorderCodes, reorderCodesLen, status);
+ 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
+ */
+
+static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ coll->reorderCodesLength = 0;
+ if (coll->reorderCodes != NULL) {
+ uprv_free(coll->reorderCodes);
+ }
+
+ if (parser->reorderCodesLength == 0 || parser->reorderCodes == NULL) {
+ return;
+ }
+
+ coll->reorderCodesLength = parser->reorderCodesLength;
+ coll->reorderCodes = (int32_t*) uprv_malloc(coll->reorderCodesLength * sizeof(int32_t));
+ uprv_memcpy(coll->reorderCodes, parser->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
+}
+
+static int ucol_getLeadBytesForReorderCode(UCollator *coll, int reorderCode, uint16_t* returnLeadBytes, int returnCapacity) {
+ uint16_t reorderCodeIndexLength = *((uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->scriptToLeadByte));
+ uint16_t* reorderCodeIndex = (uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->scriptToLeadByte + 2 *sizeof(uint16_t));
+
+ // TODO - replace with a binary search
+ // 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;
+}
+
+static int ucol_getReorderCodesForLeadByte(UCollator *coll, int leadByte, int16_t* returnReorderCodes, int returnCapacity) {
+ int leadByteIndexLength = *((uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->leadByteToScript));
+ uint16_t* leadByteIndex = (uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->leadByteToScript + 2 *sizeof(uint16_t));
+ if (leadByte >= leadByteIndexLength) {
+ return 0;
+ }
+
+ if ((leadByteIndex[leadByte] & 0x8000) == 0x8000) {
+ // offset isn't offset but instead is a single data element
+ if (returnCapacity >= 1) {
+ returnReorderCodes[0] = leadByteIndex[leadByte] & ~0x8000;
+ return 1;
+ }
+ return 0;
+ }
+ uint16_t* dataOffsetBase = (uint16_t*) ((uint8_t *)leadByteIndex + leadByteIndexLength * (2 * sizeof(uint16_t)));
+ uint16_t reorderCodeCount = *(dataOffsetBase + leadByteIndex[leadByte]);
+ reorderCodeCount = reorderCodeCount > returnCapacity ? returnCapacity : reorderCodeCount;
+ uprv_memcpy(returnReorderCodes, dataOffsetBase + leadByteIndex[leadByte] + 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;
+
+void 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;
+
+ // 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 || coll->reorderCodesLength == 0) {
+ if (coll != NULL) {
+ if (coll->leadBytePermutationTable != NULL) {
+ uprv_free(coll->leadBytePermutationTable);
+ coll->leadBytePermutationTable = NULL;
+ }
+ coll->reorderCodesLength = 0;
+ }
+ return;
+ }
+
+ if (coll->leadBytePermutationTable == NULL) {
+ coll->leadBytePermutationTable = (uint8_t*)uprv_malloc(256*sizeof(uint8_t));
+ 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) {
+ 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 reorderCodesIndex = 0; reorderCodesIndex < internalReorderCodesLength; reorderCodesIndex++) {
+ 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) {
+ uprv_free(coll->leadBytePermutationTable);
+ coll->leadBytePermutationTable = NULL;
+ }
+ coll->reorderCodesLength = 0;
+ if (internalReorderCodes != NULL) {
+ uprv_free(internalReorderCodes);
+ }
+ return;
+ }
+ fromTheBottom = false;
+ continue;
+ }
+
+ uint16_t leadByteCount = ucol_getLeadBytesForReorderCode(coll, 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) {
+ 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) {
+ 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.6/i18n/ucol_sit.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_sit.cpp
new file mode 100644
index 00000000000..45f24ea9fe7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_sit.cpp
@@ -0,0 +1,911 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2010, 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.6/i18n/ucol_tok.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_tok.cpp
new file mode 100644
index 00000000000..811d5527ccf
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_tok.cpp
@@ -0,0 +1,2452 @@
+/*
+*******************************************************************************
+*
+* 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 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 "ucol_bld.h"
+#include "ucol_tok.h"
+#include "ulocimp.h"
+#include "uresimp.h"
+#include "util.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 && (u_isWhitespace(*start) || uprv_isRuleWhiteSpace(*start))) { /* eat whitespace */
+ start++;
+ }
+ if(start >= end) {
+ return NULL;
+ }
+ /* skip opening '[' */
+ if(*start == 0x005b) {
+ start++;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR; // no opening '['
+ return NULL;
+ }
+
+ while(i < UTOK_OPTION_COUNT) {
+ if(u_strncmpNoCase(start, rulesOptions[i].optionName, rulesOptions[i].optionLen) == 0) {
+ foundOption = TRUE;
+ if(end - start > rulesOptions[i].optionLen) {
+ optionArg = start+rulesOptions[i].optionLen+1; /* start of the options, skip space */
+ while(u_isWhitespace(*optionArg) || uprv_isRuleWhiteSpace(*optionArg)) { /* eat whitespace */
+ optionArg++;
+ }
+ }
+ break;
+ }
+ i++;
+ }
+
+ if(!foundOption) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ if(optionArg) {
+ for(j = 0; j<rulesOptions[i].subSize; j++) {
+ if(u_strncmpNoCase(optionArg, rulesOptions[i].subopts[j].subName, rulesOptions[i].subopts[j].subLen) == 0) {
+ //ucol_uprv_tok_setOptionInImage(src->opts, rulesOptions[i].attr, rulesOptions[i].subopts[j].attrVal);
+ *attrib = rulesOptions[i].attr;
+ *value = rulesOptions[i].subopts[j].attrVal;
+ optionArg += rulesOptions[i].subopts[j].subLen;
+ while(u_isWhitespace(*optionArg) || uprv_isRuleWhiteSpace(*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(u_isWhitespace(*start) || uprv_isRuleWhiteSpace(*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(u_isWhitespace(**optionArg) || uprv_isRuleWhiteSpace(**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(!uprv_isRuleWhiteSpace(ch)) {
+ /* Sets the strength for this entry */
+ switch (ch) {
+ case 0x003D/*'='*/ :
+ if (newStrength != UCOL_TOK_UNSET) {
+ goto EndOfLoop;
+ }
+
+ /* if we start with strength, we'll reset to top */
+ if(startOfRules == TRUE) {
+ src->parsedToken.indirectIndex = 5;
+ top = ucol_tok_doSetTop(src, status);
+ newStrength = UCOL_TOK_RESET;
+ goto EndOfLoop;
+ }
+ newStrength = UCOL_IDENTICAL;
+ 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 (uprv_isRuleWhiteSpace(ch));
+ break;
+
+ //charsOffset = 0;
+ //newCharsLen = 0;
+ //break; // We want to store the whole prefix/character sequence. If we break
+ // the '|' is going to get lost.
+
+ case 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 || !uprv_isRuleWhiteSpace(ch)) {
+ ucol_tok_addToExtraCurrent(src, &ch, 1, status);
+ }
+ }
+ }
+
+ src->current++;
+ }
+
+EndOfLoop:
+ wasInQuote = FALSE;
+ if (newStrength == UCOL_TOK_UNSET) {
+ return NULL;
+ }
+
+ if (src->parsedToken.charsLen == 0 && top == FALSE) {
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ *status = U_INVALID_FORMAT_ERROR;
+ 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(uprv_isRuleWhiteSpace(*(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.6/i18n/ucol_tok.h b/Build/source/libs/icu/icu-4.6/i18n/ucol_tok.h
new file mode 100644
index 00000000000..838ecd0f9b9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_tok.h
@@ -0,0 +1,211 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2010, 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);
+
+U_CFUNC const UChar* 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.6/i18n/ucol_wgt.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucol_wgt.cpp
new file mode 100644
index 00000000000..5833ea3183d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucol_wgt.cpp
@@ -0,0 +1,564 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2010, 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;
+ mask=((uint32_t)0xffffffff)>>idx;
+ 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.6/i18n/ucol_wgt.h b/Build/source/libs/icu/icu-4.6/i18n/ucol_wgt.h
new file mode 100644
index 00000000000..b3cb4c9b4f6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucoleitr.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucoleitr.cpp
new file mode 100644
index 00000000000..00dfea86e12
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucoleitr.cpp
@@ -0,0 +1,784 @@
+/*
+******************************************************************************
+* Copyright (C) 2001-2010, 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 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.6/i18n/ucsdet.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucsdet.cpp
new file mode 100644
index 00000000000..d06dd336428
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ucurr.cpp b/Build/source/libs/icu/icu-4.6/i18n/ucurr.cpp
new file mode 100644
index 00000000000..1fb24b14c72
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ucurr.cpp
@@ -0,0 +1,2258 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2010, 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
+
+//------------------------------------------------------------
+// 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};
+
+//------------------------------------------------------------
+// Code
+
+/**
+ * Unfortunately, we have to convert the UChar* currency code to char*
+ * to use it as a resource key.
+ */
+static inline char*
+myUCharsToChars(char* resultOfLen4, const UChar* currency) {
+ u_UCharsToChars(currency, resultOfLen4, ISO_COUNTRY_CODE_LENGTH);
+ resultOfLen4[ISO_COUNTRY_CODE_LENGTH] = 0;
+ return resultOfLen4;
+}
+
+/**
+ * Internal function to look up currency data. Result is an array of
+ * two integers. The first is the fraction digits. The second is the
+ * rounding increment, or 0 if none. The rounding increment is in
+ * units of 10^(-fraction_digits).
+ */
+static const int32_t*
+_findMetaData(const UChar* currency, UErrorCode& ec) {
+
+ if (currency == 0 || *currency == 0) {
+ if (U_SUCCESS(ec)) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return LAST_RESORT_DATA;
+ }
+
+ // Get CurrencyMeta resource out of root locale file. [This may
+ // move out of the root locale file later; if it does, update this
+ // code.]
+ UResourceBundle* currencyData = ures_openDirect(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
+
+#if !UCONFIG_NO_SERVICE
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void);
+U_CDECL_END
+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);
+ }
+};
+
+/**
+ * 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.
+ */
+ currency_cache_cleanup();
+ return TRUE;
+}
+U_CDECL_END
+
+// -------------------------------------
+
+U_CAPI UCurrRegistryKey U_EXPORT2
+ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
+{
+ if (status && U_SUCCESS(*status)) {
+ char id[ULOC_FULLNAME_CAPACITY];
+ idForLocale(locale, id, sizeof(id), status);
+ return CReg::reg(isoCode, id, status);
+ }
+ return NULL;
+}
+
+// -------------------------------------
+
+U_CAPI UBool U_EXPORT2
+ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
+{
+ if (status && U_SUCCESS(*status)) {
+ return CReg::unreg(key);
+ }
+ return FALSE;
+}
+#endif /* UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+
+U_CAPI int32_t U_EXPORT2
+ucurr_forLocale(const char* locale,
+ UChar* buff,
+ int32_t buffCapacity,
+ UErrorCode* ec)
+{
+ int32_t resLen = 0;
+ const UChar* s = NULL;
+ if (ec != NULL && U_SUCCESS(*ec)) {
+ if ((buff && buffCapacity) || !buffCapacity) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ char id[ULOC_FULLNAME_CAPACITY];
+ if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
+ // there is a currency keyword. Try to see if it's valid
+ if(buffCapacity > resLen) {
+ /* 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_NON_DEPRECATED},
+ {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"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 const UEnumeration gEnumCurrencyList = {
+ NULL,
+ NULL,
+ ucurr_closeCurrencyList,
+ ucurr_countCurrencyList,
+ uenum_unextDefault,
+ ucurr_nextCurrencyList,
+ ucurr_resetCurrencyList
+};
+U_CDECL_END
+
+U_CAPI UEnumeration * U_EXPORT2
+ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
+ UEnumeration *myEnum = NULL;
+ UCurrencyContext *myContext;
+
+ myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
+ if (myEnum == NULL) {
+ *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
+ myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
+ if (myContext == NULL) {
+ *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(myEnum);
+ return NULL;
+ }
+ myContext->currType = currType;
+ myContext->listIdx = 0;
+ myEnum->context = myContext;
+ return myEnum;
+}
+
+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.6/i18n/ucurrimp.h b/Build/source/libs/icu/icu-4.6/i18n/ucurrimp.h
new file mode 100644
index 00000000000..98871ce4c39
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/udat.cpp b/Build/source/libs/icu/icu-4.6/i18n/udat.cpp
new file mode 100644
index 00000000000..758a6a7e113
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/udat.cpp
@@ -0,0 +1,962 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2010, 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)
+{
+ verifyIsSimpleDateFormat(fmt, status);
+ if(U_FAILURE(*status)) return -1;
+
+ const DateFormatSymbols *syms =
+ ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
+ int32_t count;
+ const UnicodeString *res = NULL;
+
+ switch(type) {
+ case UDAT_ERAS:
+ res = syms->getEras(count);
+ break;
+
+ case UDAT_ERA_NAMES:
+ res = syms->getEraNames(count);
+ break;
+
+ case UDAT_MONTHS:
+ res = syms->getMonths(count);
+ break;
+
+ case UDAT_SHORT_MONTHS:
+ res = syms->getShortMonths(count);
+ break;
+
+ case UDAT_WEEKDAYS:
+ res = syms->getWeekdays(count);
+ break;
+
+ case UDAT_SHORT_WEEKDAYS:
+ res = syms->getShortWeekdays(count);
+ break;
+
+ case UDAT_AM_PMS:
+ res = syms->getAmPmStrings(count);
+ break;
+
+ case UDAT_LOCALIZED_CHARS:
+ {
+ UnicodeString res1;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res1.setTo(result, 0, resultLength);
+ }
+ syms->getLocalPatternChars(res1);
+ return res1.extract(result, resultLength, *status);
+ }
+
+ case UDAT_NARROW_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_NARROW_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_SHORT_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ }
+
+ if(index < count) {
+ return res[index].extract(result, resultLength, *status);
+ }
+ return 0;
+}
+
+// TODO: also needs an errorCode.
+U_CAPI int32_t U_EXPORT2
+udat_countSymbols( const UDateFormat *fmt,
+ UDateFormatSymbolType type)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ verifyIsSimpleDateFormat(fmt, &status);
+ if(U_FAILURE(status)) {
+ return 0;
+ }
+
+ const DateFormatSymbols *syms =
+ ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
+ int32_t count = 0;
+
+ switch(type) {
+ case UDAT_ERAS:
+ syms->getEras(count);
+ break;
+
+ case UDAT_MONTHS:
+ syms->getMonths(count);
+ break;
+
+ case UDAT_SHORT_MONTHS:
+ syms->getShortMonths(count);
+ break;
+
+ case UDAT_WEEKDAYS:
+ syms->getWeekdays(count);
+ break;
+
+ case UDAT_SHORT_WEEKDAYS:
+ syms->getShortWeekdays(count);
+ break;
+
+ case UDAT_AM_PMS:
+ syms->getAmPmStrings(count);
+ break;
+
+ case UDAT_LOCALIZED_CHARS:
+ count = 1;
+ break;
+
+ case UDAT_ERA_NAMES:
+ syms->getEraNames(count);
+ break;
+
+ case UDAT_NARROW_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_NARROW_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_SHORT_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ }
+
+ return count;
+}
+
+U_NAMESPACE_BEGIN
+
+/*
+ * This DateFormatSymbolsSingleSetter class is a friend of DateFormatSymbols
+ * solely for the purpose of avoiding to clone the array of strings
+ * just to modify one of them and then setting all of them back.
+ * For example, the old code looked like this:
+ * case UDAT_MONTHS:
+ * res = syms->getMonths(count);
+ * array = new UnicodeString[count];
+ * if(array == 0) {
+ * *status = U_MEMORY_ALLOCATION_ERROR;
+ * return;
+ * }
+ * uprv_arrayCopy(res, array, count);
+ * if(index < count)
+ * array[index] = val;
+ * syms->setMonths(array, count);
+ * break;
+ *
+ * Even worse, the old code actually cloned the entire DateFormatSymbols object,
+ * cloned one value array, changed one value, and then made the SimpleDateFormat
+ * replace its DateFormatSymbols object with the new one.
+ *
+ * markus 2002-oct-14
+ */
+class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ {
+public:
+ static void
+ setSymbol(UnicodeString *array, int32_t count, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ if(array!=NULL) {
+ if(index>=count) {
+ errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+ } else if(value==NULL) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ array[index].setTo(value, valueLength);
+ }
+ }
+ }
+
+ static void
+ setEra(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setEraName(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fEraNames, syms->fEraNamesCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setShortMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setNarrowMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fNarrowMonths, syms->fNarrowMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneMonths, syms->fStandaloneMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneShortMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneShortMonths, syms->fStandaloneShortMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneNarrowMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneNarrowMonths, syms->fStandaloneNarrowMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setShortWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setNarrowWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fNarrowWeekdays, syms->fNarrowWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneWeekdays, syms->fStandaloneWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneShortWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneShortWeekdays, syms->fStandaloneShortWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneNarrowWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneNarrowWeekdays, syms->fStandaloneNarrowWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fQuarters, syms->fQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setShortQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneQuarters, syms->fStandaloneQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneShortQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setAmPm(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setLocalPatternChars(DateFormatSymbols *syms,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode);
+ }
+};
+
+U_NAMESPACE_END
+
+U_CAPI void U_EXPORT2
+udat_setSymbols( UDateFormat *format,
+ UDateFormatSymbolType type,
+ int32_t index,
+ UChar *value,
+ int32_t valueLength,
+ UErrorCode *status)
+{
+ 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.6/i18n/udatpg.cpp b/Build/source/libs/icu/icu-4.6/i18n/udatpg.cpp
new file mode 100644
index 00000000000..006384f1237
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ulocdata.c b/Build/source/libs/icu/icu-4.6/i18n/ulocdata.c
new file mode 100644
index 00000000000..20d02462987
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ulocdata.c
@@ -0,0 +1,341 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2009, 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" };
+ 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.6/i18n/umsg.cpp b/Build/source/libs/icu/icu-4.6/i18n/umsg.cpp
new file mode 100644
index 00000000000..8a58ee0442c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/umsg.cpp
@@ -0,0 +1,706 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: umsg.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* This is a C wrapper to MessageFormat C++ API.
+*
+* Change history:
+*
+* 08/5/2001 Ram Added C wrappers for C++ API. Changed implementation of old API's
+* Removed pattern parser.
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/umsg.h"
+#include "unicode/ustring.h"
+#include "unicode/fmtable.h"
+#include "unicode/msgfmt.h"
+#include "unicode/unistr.h"
+#include "cpputils.h"
+#include "uassert.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_USE
+
+U_CAPI int32_t
+u_formatMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ int32_t actLen;
+ //argument checking defered to subsequent method calls
+ // start vararg processing
+ va_start(ap, status);
+
+ actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
+ // end vararg processing
+ va_end(ap);
+
+ return actLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_vformatMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status)
+
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
+ int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
+ umsg_close(fmt);
+ return retVal;
+}
+
+U_CAPI int32_t
+u_formatMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError *parseError,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ int32_t actLen;
+ //argument checking defered to subsequent method calls
+ // start vararg processing
+ va_start(ap, status);
+
+ actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
+
+ // end vararg processing
+ va_end(ap);
+ return actLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_vformatMessageWithError( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError *parseError,
+ va_list ap,
+ UErrorCode *status)
+
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status);
+ int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
+ umsg_close(fmt);
+ return retVal;
+}
+
+
+// For parse, do the reverse of format:
+// 1. Call through to the C++ APIs
+// 2. Just assume the user passed in enough arguments.
+// 3. Iterate through each formattable returned, and assign to the arguments
+U_CAPI void
+u_parseMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ //argument checking defered to subsequent method calls
+
+ // start vararg processing
+ va_start(ap, status);
+
+ u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
+ // end vararg processing
+ va_end(ap);
+}
+
+U_CAPI void U_EXPORT2
+u_vparseMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UErrorCode *status)
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
+ int32_t count = 0;
+ umsg_vparse(fmt,source,sourceLength,&count,ap,status);
+ umsg_close(fmt);
+}
+
+U_CAPI void
+u_parseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UParseError *error,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+
+ //argument checking defered to subsequent method calls
+
+ // start vararg processing
+ va_start(ap, status);
+
+ u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
+ // end vararg processing
+ va_end(ap);
+}
+U_CAPI void U_EXPORT2
+u_vparseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UParseError *error,
+ UErrorCode* status)
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
+ int32_t count = 0;
+ umsg_vparse(fmt,source,sourceLength,&count,ap,status);
+ umsg_close(fmt);
+}
+//////////////////////////////////////////////////////////////////////////////////
+//
+// Message format C API
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+
+U_CAPI UMessageFormat* U_EXPORT2
+umsg_open( const UChar *pattern,
+ int32_t patternLength,
+ const char *locale,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==NULL || U_FAILURE(*status))
+ {
+ return 0;
+ }
+ if(pattern==NULL||patternLength<-1){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UParseError tErr;
+
+ if(parseError==NULL)
+ {
+ parseError = &tErr;
+ }
+
+ UMessageFormat* retVal = 0;
+
+ int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
+
+ UnicodeString patString((patternLength == -1 ? TRUE:FALSE), pattern,len);
+
+ retVal = (UMessageFormat*) new MessageFormat(patString,Locale(locale),*parseError,*status);
+
+ if(retVal == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ return retVal;
+}
+
+U_CAPI void U_EXPORT2
+umsg_close(UMessageFormat* format)
+{
+ //check arguments
+ if(format==NULL){
+ return;
+ }
+ delete (MessageFormat*) format;
+}
+
+U_CAPI UMessageFormat U_EXPORT2
+umsg_clone(const UMessageFormat *fmt,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==NULL || U_FAILURE(*status)){
+ return NULL;
+ }
+ if(fmt==NULL){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
+ if(retVal == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ return retVal;
+}
+
+U_CAPI void U_EXPORT2
+umsg_setLocale(UMessageFormat *fmt, const char* locale)
+{
+ //check arguments
+ if(fmt==NULL){
+ return;
+ }
+ ((MessageFormat*)fmt)->setLocale(Locale(locale));
+}
+
+U_CAPI const char* U_EXPORT2
+umsg_getLocale(const UMessageFormat *fmt)
+{
+ //check arguments
+ if(fmt==NULL){
+ return "";
+ }
+ return ((const MessageFormat*)fmt)->getLocale().getName();
+}
+
+U_CAPI void U_EXPORT2
+umsg_applyPattern(UMessageFormat *fmt,
+ const UChar* pattern,
+ int32_t patternLength,
+ UParseError* parseError,
+ UErrorCode* status)
+{
+ //check arguments
+ UParseError tErr;
+ if(status ==NULL||U_FAILURE(*status)){
+ return ;
+ }
+ if(fmt==NULL||pattern==NULL||patternLength<-1){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return ;
+ }
+
+ if(parseError==NULL){
+ parseError = &tErr;
+ }
+ if(patternLength<-1){
+ patternLength=u_strlen(pattern);
+ }
+
+ ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
+}
+
+U_CAPI int32_t U_EXPORT2
+umsg_toPattern(const UMessageFormat *fmt,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status)
+{
+ //check arguments
+ if(status ==NULL||U_FAILURE(*status)){
+ return -1;
+ }
+ if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+ ((const MessageFormat*)fmt)->toPattern(res);
+ return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t
+umsg_format( const UMessageFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ int32_t actLen;
+ //argument checking defered to last method call umsg_vformat which
+ //saves time when arguments are valid and we dont care when arguments are not
+ //since we return an error anyway
+
+
+ // start vararg processing
+ va_start(ap, status);
+
+ actLen = umsg_vformat(fmt,result,resultLength,ap,status);
+
+ // end vararg processing
+ va_end(ap);
+
+ return actLen;
+}
+
+U_NAMESPACE_BEGIN
+/**
+ * This class isolates our access to private internal methods of
+ * MessageFormat. It is never instantiated; it exists only for C++
+ * access management.
+ */
+class MessageFormatAdapter {
+public:
+ static const Formattable::Type* getArgTypeList(const MessageFormat& m,
+ int32_t& count);
+};
+const Formattable::Type*
+MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
+ int32_t& count) {
+ return m.getArgTypeList(count);
+}
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+umsg_vformat( const UMessageFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==0 || U_FAILURE(*status))
+ {
+ return -1;
+ }
+ if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ int32_t count =0;
+ const Formattable::Type* argTypes =
+ MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
+ // Allocate at least one element. Allocating an array of length
+ // zero causes problems on some platforms (e.g. Win32).
+ Formattable* args = new Formattable[count ? count : 1];
+
+ // iterate through the vararg list, and get the arguments out
+ for(int32_t i = 0; i < count; ++i) {
+
+ UChar *stringVal;
+ double tDouble=0;
+ int32_t tInt =0;
+ int64_t tInt64 = 0;
+ UDate tempDate = 0;
+ switch(argTypes[i]) {
+ case Formattable::kDate:
+ tempDate = va_arg(ap, UDate);
+ args[i].setDate(tempDate);
+ break;
+
+ case Formattable::kDouble:
+ tDouble =va_arg(ap, double);
+ args[i].setDouble(tDouble);
+ break;
+
+ case Formattable::kLong:
+ tInt = va_arg(ap, int32_t);
+ args[i].setLong(tInt);
+ break;
+
+ case Formattable::kInt64:
+ tInt64 = va_arg(ap, int64_t);
+ args[i].setInt64(tInt64);
+ break;
+
+ case Formattable::kString:
+ // For some reason, a temporary is needed
+ stringVal = va_arg(ap, UChar*);
+ if(stringVal){
+ args[i].setString(stringVal);
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kArray:
+ // throw away this argument
+ // this is highly platform-dependent, and probably won't work
+ // so, if you try to skip arguments in the list (and not use them)
+ // you'll probably crash
+ va_arg(ap, int);
+ break;
+
+ case Formattable::kObject:
+ // This will never happen because MessageFormat doesn't
+ // support kObject. When MessageFormat is changed to
+ // understand MeasureFormats, modify this code to do the
+ // right thing. [alan]
+ U_ASSERT(FALSE);
+ break;
+ }
+ }
+ UnicodeString resultStr;
+ FieldPosition fieldPosition(0);
+
+ /* format the message */
+ ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
+
+ delete[] args;
+
+ if(U_FAILURE(*status)){
+ return -1;
+ }
+
+ return resultStr.extract(result, resultLength, *status);
+}
+
+U_CAPI void
+umsg_parse( const UMessageFormat *fmt,
+ const UChar *source,
+ int32_t sourceLength,
+ int32_t *count,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ //argument checking defered to last method call umsg_vparse which
+ //saves time when arguments are valid and we dont care when arguments are not
+ //since we return an error anyway
+
+ // start vararg processing
+ va_start(ap, status);
+
+ umsg_vparse(fmt,source,sourceLength,count,ap,status);
+
+ // end vararg processing
+ va_end(ap);
+}
+
+U_CAPI void U_EXPORT2
+umsg_vparse(const UMessageFormat *fmt,
+ const UChar *source,
+ int32_t sourceLength,
+ int32_t *count,
+ va_list ap,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==NULL||U_FAILURE(*status))
+ {
+ return;
+ }
+ if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if(sourceLength==-1){
+ sourceLength=u_strlen(source);
+ }
+
+ UnicodeString srcString(source,sourceLength);
+ Formattable *args = ((const MessageFormat*)fmt)->parse(source,*count,*status);
+ UDate *aDate;
+ double *aDouble;
+ UChar *aString;
+ int32_t* aInt;
+ int64_t* aInt64;
+ UnicodeString temp;
+ int len =0;
+ // assign formattables to varargs
+ for(int32_t i = 0; i < *count; i++) {
+ switch(args[i].getType()) {
+
+ case Formattable::kDate:
+ aDate = va_arg(ap, UDate*);
+ if(aDate){
+ *aDate = args[i].getDate();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kDouble:
+ aDouble = va_arg(ap, double*);
+ if(aDouble){
+ *aDouble = args[i].getDouble();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kLong:
+ aInt = va_arg(ap, int32_t*);
+ if(aInt){
+ *aInt = (int32_t) args[i].getLong();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kInt64:
+ aInt64 = va_arg(ap, int64_t*);
+ if(aInt64){
+ *aInt64 = args[i].getInt64();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kString:
+ aString = va_arg(ap, UChar*);
+ if(aString){
+ args[i].getString(temp);
+ len = temp.length();
+ temp.extract(0,len,aString);
+ aString[len]=0;
+ }else{
+ *status= U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kObject:
+ // This will never happen because MessageFormat doesn't
+ // support kObject. When MessageFormat is changed to
+ // understand MeasureFormats, modify this code to do the
+ // right thing. [alan]
+ U_ASSERT(FALSE);
+ break;
+
+ // better not happen!
+ case Formattable::kArray:
+ U_ASSERT(FALSE);
+ break;
+ }
+ }
+
+ // clean up
+ delete [] args;
+}
+
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define CURLY_BRACE_LEFT ((UChar)0x007B)
+#define CURLY_BRACE_RIGHT ((UChar)0x007D)
+
+#define STATE_INITIAL 0
+#define STATE_SINGLE_QUOTE 1
+#define STATE_IN_QUOTE 2
+#define STATE_MSG_ELEMENT 3
+
+#define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
+
+int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
+ int32_t patternLength,
+ UChar* dest,
+ int32_t destCapacity,
+ UErrorCode* ec)
+{
+ int32_t state = STATE_INITIAL;
+ int32_t braceCount = 0;
+ int32_t len = 0;
+
+ if (ec == NULL || U_FAILURE(*ec)) {
+ return -1;
+ }
+
+ if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ if (patternLength == -1) {
+ patternLength = u_strlen(pattern);
+ }
+
+ for (int i = 0; i < patternLength; ++i) {
+ UChar c = pattern[i];
+ switch (state) {
+ case STATE_INITIAL:
+ switch (c) {
+ case SINGLE_QUOTE:
+ state = STATE_SINGLE_QUOTE;
+ break;
+ case CURLY_BRACE_LEFT:
+ state = STATE_MSG_ELEMENT;
+ ++braceCount;
+ break;
+ }
+ break;
+
+ case STATE_SINGLE_QUOTE:
+ switch (c) {
+ case SINGLE_QUOTE:
+ state = STATE_INITIAL;
+ break;
+ case CURLY_BRACE_LEFT:
+ case CURLY_BRACE_RIGHT:
+ state = STATE_IN_QUOTE;
+ break;
+ default:
+ MAppend(SINGLE_QUOTE);
+ state = STATE_INITIAL;
+ break;
+ }
+ break;
+
+ case STATE_IN_QUOTE:
+ switch (c) {
+ case SINGLE_QUOTE:
+ state = STATE_INITIAL;
+ break;
+ }
+ break;
+
+ case STATE_MSG_ELEMENT:
+ switch (c) {
+ case CURLY_BRACE_LEFT:
+ ++braceCount;
+ break;
+ case CURLY_BRACE_RIGHT:
+ if (--braceCount == 0) {
+ state = STATE_INITIAL;
+ }
+ break;
+ }
+ break;
+
+ default: // Never happens.
+ break;
+ }
+
+ MAppend(c);
+ }
+
+ // End of scan
+ if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
+ MAppend(SINGLE_QUOTE);
+ }
+
+ return u_terminateUChars(dest, destCapacity, len, ec);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/umsg_imp.h b/Build/source/libs/icu/icu-4.6/i18n/umsg_imp.h
new file mode 100644
index 00000000000..78bbf966bce
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unesctrn.cpp b/Build/source/libs/icu/icu-4.6/i18n/unesctrn.cpp
new file mode 100644
index 00000000000..c3d848d06e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unesctrn.h b/Build/source/libs/icu/icu-4.6/i18n/unesctrn.h
new file mode 100644
index 00000000000..bfde6fc134f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/uni2name.cpp b/Build/source/libs/icu/icu-4.6/i18n/uni2name.cpp
new file mode 100644
index 00000000000..5eba79daceb
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/uni2name.h b/Build/source/libs/icu/icu-4.6/i18n/uni2name.h
new file mode 100644
index 00000000000..aede864564a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/basictz.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/basictz.h
new file mode 100644
index 00000000000..f3d34a663c7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/bms.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/bms.h
new file mode 100644
index 00000000000..516e6aa2280
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/bmsearch.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/bmsearch.h
new file mode 100644
index 00000000000..b5973e579c0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/calendar.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/calendar.h
new file mode 100644
index 00000000000..5aa5ff9df6f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/calendar.h
@@ -0,0 +1,2252 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, 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;
+
+ /**
+ * 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.6/i18n/unicode/choicfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/choicfmt.h
new file mode 100644
index 00000000000..921b0a984ee
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/choicfmt.h
@@ -0,0 +1,749 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File CHOICFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation and got rid
+* of nextDouble/previousDouble and replaced with
+* boolean array.
+* 4/10/97 aliu Clean up. Modified to work on AIX.
+* 8/6/97 nos Removed overloaded constructor, member var 'buffer'.
+* 07/22/98 stephen Removed operator!= (implemented in Format)
+********************************************************************************
+*/
+
+#ifndef CHOICFMT_H
+#define CHOICFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Choice Format.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/numfmt.h"
+#include "unicode/fieldpos.h"
+#include "unicode/format.h"
+
+U_NAMESPACE_BEGIN
+
+class MessageFormat;
+
+/**
+ * ChoiceFormat converts between ranges of numeric values
+ * and string names for those ranges. A <code>ChoiceFormat</code> splits
+ * the real number line <code>-Inf</code> to <code>+Inf</code> into two
+ * or more contiguous ranges. Each range is mapped to a
+ * string. <code>ChoiceFormat</code> is generally used in a
+ * <code>MessageFormat</code> for displaying grammatically correct
+ * plurals such as &quot;There are 2 files.&quot;</p>
+ *
+ * <p>There are two methods of defining a <code>ChoiceFormat</code>; both
+ * are equivalent. The first is by using a string pattern. This is the
+ * preferred method in most cases. The second method is through direct
+ * specification of the arrays that make up the
+ * <code>ChoiceFormat</code>.</p>
+ *
+ * <p><strong>Patterns</strong></p>
+ *
+ * <p>In most cases, the preferred way to define a
+ * <code>ChoiceFormat</code> is with a pattern. Here is an example of a
+ * <code>ChoiceFormat</code> pattern:</p>
+ *
+ * \htmlonly<pre> 0&#x2264;are no files|1&#x2264;is one file|1&lt;are many files</pre>\endhtmlonly
+ *
+ * <p>or equivalently,</p>
+ *
+ * \htmlonly<pre> 0#are no files|1#is one file|1&lt;are many files</pre>\endhtmlonly
+ *
+ * <p>The pattern consists of a number or <em>range specifiers</em>
+ * separated by vertical bars '|' (U+007C). There is no
+ * vertical bar after the last range. Each range specifier is of the
+ * form:</p>
+ *
+ * \htmlonly<blockquote><em>Number Separator String</em></blockquote>\endhtmlonly
+ *
+ * <p><em>Number</em> is a floating point number that can be parsed by a
+ * default <code>NumberFormat</code> for the US locale. It gives the
+ * lower limit of this range. The lower limit is either inclusive or
+ * exclusive, depending on the <em>separator</em>. The upper limit is
+ * given by the lower limit of the next range. The Unicode infinity
+ * sign \htmlonly&#x221E \endhtmlonly (U+221E) is recognized for positive infinity. It may be preceded by
+ * '-' (U+002D) to indicate negative infinity.</p>
+ *
+ * <p><em>String</em> is the format string for this range, with special
+ * characters enclosed in single quotes (<code>'The #
+ * sign'</code>). Single quotes themselves are indicated by two single
+ * quotes in a row (<code>'o''clock'</code>).</p>
+ *
+ * <p><em>Separator</em> is one of the following single characters:
+ *
+ * <ul>
+ * <li>\htmlonly'&#x2264;' \endhtmlonly (U+2264) or '#' (U+0023)
+ * indicates that the lower limit given by <em>Number</em> is
+ * inclusive. (The two characters are equivalent to ChoiceFormat.)
+ * This means that the limit value <em>Number</em> belongs to this
+ * range. Another way of saying this is that the corresponding
+ * closure is <code>FALSE</code>.</li>
+ *
+ * <li>'<' (U+003C) indicates that the lower limit given by
+ * <em>Number</em> is exclusive. This means that the value
+ * <em>Number</em> belongs to the prior range.</li> Another way of
+ * saying this is that the corresponding closure is
+ * <code>TRUE</code>.
+ * </ul>
+ *
+ * <p>See below for more information about closures.</p>
+ *
+ * <p><strong>Arrays</strong></p>
+ *
+ * <p>A <code>ChoiceFormat</code> defining <code>n</code> intervals
+ * (<code>n</code> &gt;= 2) is specified by three arrays of
+ * <code>n</code> items:
+ *
+ * <ul>
+ * <li><code>double limits[]</code> gives the start of each
+ * interval. This must be a non-decreasing list of values, none of
+ * which may be <code>NaN</code>.</li>
+ * <li><code>UBool closures[]</code> determines whether each limit
+ * value is contained in the interval below it or in the interval
+ * above it. If <code>closures[i]</code> is <code>FALSE</code>, then
+ * <code>limits[i]</code> is a member of interval
+ * <code>i</code>. Otherwise it is a member of interval
+ * <code>i+1</code>. If no closures array is specified, this is
+ * equivalent to having all closures be <code>FALSE</code>. Closures
+ * allow one to specify half-open, open, or closed intervals.</li>
+ * <li><code>UnicodeString formats[]</code> gives the string label
+ * associated with each interval.</li>
+ * </ul>
+ *
+ * <p><strong>Formatting and Parsing</strong></p>
+ *
+ * <p>During formatting, a number is converted to a
+ * string. <code>ChoiceFormat</code> accomplishes this by mapping the
+ * number to an interval using the following rule. Given a number
+ * <code>X</code> and and index value <code>j</code> in the range
+ * <code>0..n-1</code>, where <code>n</code> is the number of ranges:</p>
+ *
+ * \htmlonly<blockquote>\endhtmlonly<code>X</code> matches <code>j</code> if and only if
+ * <code>limit[j] &lt;= X &lt; limit[j+1]</code>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <p>(This assumes that all closures are <code>FALSE</code>. If some
+ * closures are <code>TRUE</code> then the relations must be changed to
+ * <code>&lt;=</code> or <code>&lt;</code> as appropriate.) If there is
+ * no match, then either the first or last index is used, depending on
+ * whether the number is too low or too high. Once a number is mapped to
+ * an interval <code>j</code>, the string <code>formats[j]</code> is
+ * output.</p>
+ *
+ * <p>During parsing, a string is converted to a
+ * number. <code>ChoiceFormat</code> finds the element
+ * <code>formats[j]</code> equal to the string, and returns
+ * <code>limits[j]</code> as the parsed value.</p>
+ *
+ * <p><strong>Notes</strong></p>
+ *
+ * <p>The first limit value does not define a range boundary. For
+ * example, in the pattern \htmlonly&quot;<code>1.0#a|2.0#b</code>&quot;\endhtmlonly, the
+ * intervals are [-Inf, 2.0) and [2.0, +Inf]. It appears that the first
+ * interval should be [1.0, 2.0). However, since all values that are too
+ * small are mapped to range zero, the first interval is effectively
+ * [-Inf, 2.0). However, the first limit value <em>is</em> used during
+ * formatting. In this example, <code>parse(&quot;a&quot;)</code> returns
+ * 1.0.</p>
+ *
+ * <p>There are no gaps between intervals and the entire number line is
+ * covered. A <code>ChoiceFormat</code> maps <em>all</em> possible
+ * double values to a finite set of intervals.</p>
+ *
+ * <p>The non-number <code>NaN</code> is mapped to interval zero during
+ * formatting.</p>
+ *
+ * <p><strong>Examples</strong></p>
+ *
+ * <p>Here is an example of two arrays that map the number
+ * <code>1..7</code> to the English day of the week abbreviations
+ * <code>Sun..Sat</code>. No closures array is given; this is the same as
+ * specifying all closures to be <code>FALSE</code>.</p>
+ *
+ * <pre> {1,2,3,4,5,6,7},
+ * {&quot;Sun&quot;,&quot;Mon&quot;,&quot;Tue&quot;,&quot;Wed&quot;,&quot;Thur&quot;,&quot;Fri&quot;,&quot;Sat&quot;}</pre>
+ *
+ * <p>Here is an example that maps the ranges [-Inf, 1), [1, 1], and (1,
+ * +Inf] to three strings. That is, the number line is split into three
+ * ranges: x &lt; 1.0, x = 1.0, and x &gt; 1.0.</p>
+ *
+ * <pre> {0, 1, 1},
+ * {FALSE, FALSE, TRUE},
+ * {&quot;no files&quot;, &quot;one file&quot;, &quot;many files&quot;}</pre>
+ *
+ * <p>Here is a simple example that shows formatting and parsing: </p>
+ *
+ * \code
+ * #include <unicode/choicfmt.h>
+ * #include <unicode/unistr.h>
+ * #include <iostream.h>
+ *
+ * int main(int argc, char *argv[]) {
+ * double limits[] = {1,2,3,4,5,6,7};
+ * UnicodeString monthNames[] = {
+ * "Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
+ * ChoiceFormat fmt(limits, monthNames, 7);
+ * UnicodeString str;
+ * char buf[256];
+ * for (double x = 1.0; x <= 8.0; x += 1.0) {
+ * fmt.format(x, str);
+ * str.extract(0, str.length(), buf, 256, "");
+ * str.truncate(0);
+ * cout << x << " -> "
+ * << buf << endl;
+ * }
+ * cout << endl;
+ * return 0;
+ * }
+ * \endcode
+ *
+ * <p>Here is a more complex example using a <code>ChoiceFormat</code>
+ * constructed from a pattern together with a
+ * <code>MessageFormat</code>.</p>
+ *
+ * \code
+ * #include <unicode/choicfmt.h>
+ * #include <unicode/msgfmt.h>
+ * #include <unicode/unistr.h>
+ * #include <iostream.h>
+ *
+ * int main(int argc, char *argv[]) {
+ * UErrorCode status = U_ZERO_ERROR;
+ * double filelimits[] = {0,1,2};
+ * UnicodeString filepart[] =
+ * {"are no files","is one file","are {0} files"};
+ * ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3 );
+ * Format* testFormats[] =
+ * {fileform, NULL, NumberFormat::createInstance(status)};
+ * MessageFormat pattform("There {0} on {1}", status );
+ * pattform.adoptFormats(testFormats, 3);
+ * Formattable testArgs[] = {0L, "Disk A"};
+ * FieldPosition fp(0);
+ * UnicodeString str;
+ * char buf[256];
+ * for (int32_t i = 0; i < 4; ++i) {
+ * Formattable fInt(i);
+ * testArgs[0] = fInt;
+ * pattform.format(testArgs, 2, str, fp, status );
+ * str.extract(0, str.length(), buf, "");
+ * str.truncate(0);
+ * cout << "Output for i=" << i << " : " << buf << endl;
+ * }
+ * cout << endl;
+ * return 0;
+ * }
+ * \endcode
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API ChoiceFormat: public NumberFormat {
+public:
+ /**
+ * Construct a new ChoiceFormat with the limits and the corresponding formats
+ * based on the pattern.
+ *
+ * @param pattern Pattern used to construct object.
+ * @param status Output param to receive success code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ ChoiceFormat(const UnicodeString& pattern,
+ UErrorCode& status);
+
+
+ /**
+ * Construct a new ChoiceFormat with the given limits and formats. Copy
+ * the limits and formats instead of adopting them.
+ *
+ * @param limits Array of limit values.
+ * @param formats Array of formats.
+ * @param count Size of 'limits' and 'formats' arrays.
+ * @stable ICU 2.0
+ */
+
+ ChoiceFormat(const double* limits,
+ const UnicodeString* formats,
+ int32_t count );
+
+ /**
+ * Construct a new ChoiceFormat with the given limits and formats.
+ * Copy the limits and formats (instead of adopting them). By
+ * default, each limit in the array specifies the inclusive lower
+ * bound of its range, and the exclusive upper bound of the previous
+ * range. However, if the isLimitOpen element corresponding to a
+ * limit is TRUE, then the limit is the exclusive lower bound of its
+ * range, and the inclusive upper bound of the previous range.
+ * @param limits Array of limit values
+ * @param closures Array of booleans specifying whether each
+ * element of 'limits' is open or closed. If FALSE, then the
+ * corresponding limit is a member of the range above it. If TRUE,
+ * then the limit belongs to the range below it.
+ * @param formats Array of formats
+ * @param count Size of 'limits', 'closures', and 'formats' arrays
+ * @stable ICU 2.4
+ */
+ ChoiceFormat(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t count);
+
+ /**
+ * Copy constructor.
+ *
+ * @param that ChoiceFormat object to be copied from
+ * @stable ICU 2.0
+ */
+ ChoiceFormat(const ChoiceFormat& that);
+
+ /**
+ * Assignment operator.
+ *
+ * @param that ChoiceFormat object to be copied
+ * @stable ICU 2.0
+ */
+ const ChoiceFormat& operator=(const ChoiceFormat& that);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~ChoiceFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ *
+ * @return a copy of this object
+ * @stable ICU 2.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ *
+ * @param other ChoiceFormat object to be compared
+ * @return true if other is the same as this.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Sets the pattern.
+ * @param pattern The pattern to be applied.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Sets the pattern.
+ * @param pattern The pattern to be applied.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Gets the pattern.
+ *
+ * @param pattern Output param which will recieve the pattern
+ * Previous contents are deleted.
+ * @return A reference to 'pattern'
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString &pattern) const;
+
+ /**
+ * Set the choices to be used in formatting.
+ *
+ * @param limitsToCopy Contains the top value that you want
+ * parsed with that format,and should be in
+ * ascending sorted order. When formatting X,
+ * the choice will be the i, where limit[i]
+ * &lt;= X &lt; limit[i+1].
+ * @param formatsToCopy The format strings you want to use for each limit.
+ * @param count The size of the above arrays.
+ * @stable ICU 2.0
+ */
+ virtual void setChoices(const double* limitsToCopy,
+ const UnicodeString* formatsToCopy,
+ int32_t count );
+
+ /**
+ * Set the choices to be used in formatting. See class description
+ * for documenatation of the limits, closures, and formats arrays.
+ * @param limits Array of limits
+ * @param closures Array of limit booleans
+ * @param formats Array of format string
+ * @param count The size of the above arrays
+ * @stable ICU 2.4
+ */
+ virtual void setChoices(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t count);
+
+ /**
+ * Get the limits passed in the constructor.
+ *
+ * @param count The size of the limits arrays
+ * @return the limits.
+ * @stable ICU 2.0
+ */
+ virtual const double* getLimits(int32_t& count) const;
+
+ /**
+ * Get the limit booleans passed in the constructor. The caller
+ * must not delete the result.
+ *
+ * @param count The size of the arrays
+ * @return the closures
+ * @stable ICU 2.4
+ */
+ virtual const UBool* getClosures(int32_t& count) const;
+
+ /**
+ * Get the formats passed in the constructor.
+ *
+ * @param count The size of the arrays
+ * @return the formats.
+ * @stable ICU 2.0
+ */
+ virtual const UnicodeString* getFormats(int32_t& count) const;
+
+
+ using NumberFormat::format;
+
+ /**
+ * Format a double or long number using this object's choices.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Format a int_32t number using this object's choices.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an int64_t number using this object's choices.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.8
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an array of objects using this object's choices.
+ *
+ * @param objs The array of objects to be formatted.
+ * @param cnt The size of objs.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param success Output param set to success/failure code on
+ * exit.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable* objs,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& success) const;
+ /**
+ * Format an object using this object's choices.
+ *
+ *
+ * @param obj The object to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param set to success/failure code on
+ * exit.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ *
+ * @param obj The object to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Output param set to success/failure code on
+ * exit.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format a double number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( double number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format a long number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( int32_t number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Return a long if possible (e.g. within range LONG_MAX,
+ * LONG_MAX], and with no decimals), otherwise a double. If
+ * IntegerOnly is set, will stop at a decimal point (or equivalent;
+ * e.g. for rational numbers "1 2/3", will stop after the 1).
+ * <P>
+ * If no object can be parsed, parsePosition is unchanged, and NULL is
+ * returned.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parsePosition The position to start parsing at on input.
+ * On output, moved to after the last successfully
+ * parse character. On parse failure, does not change.
+ * @see NumberFormat::isParseIntegerOnly
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const;
+
+ /**
+ * Return a long if possible (e.g. within range LONG_MAX,
+ * LONG_MAX], and with no decimals), otherwise a double. If
+ * IntegerOnly is set, will stop at a decimal point (or equivalent;
+ * e.g. for rational numbers "1 2/3", will stop after the 1).
+ * <P>
+ * If no object can be parsed, parsePosition is unchanged, and NULL is
+ * returned.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param status Output param with the formatted string.
+ * @see NumberFormat::isParseIntegerOnly
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const;
+
+
+public:
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
+ * This method is to implement a simple version of RTTI, since not all
+ * C++ compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+private:
+ // static cache management (thread-safe)
+ // static NumberFormat* getNumberFormat(UErrorCode &status); // call this function to 'check out' a numberformat from the cache.
+ // static void releaseNumberFormat(NumberFormat *adopt); // call this function to 'return' the number format to the cache.
+
+ /**
+ * Converts a string to a double value using a default NumberFormat object
+ * which is static (shared by all ChoiceFormat instances).
+ * @param string the string to be converted with.
+ * @return the converted double number.
+ */
+ static double stod(const UnicodeString& string);
+
+ /**
+ * Converts a double value to a string using a default NumberFormat object
+ * which is static (shared by all ChoiceFormat instances).
+ * @param value the double number to be converted with.
+ * @param string the result string.
+ * @return the converted string.
+ */
+ static UnicodeString& dtos(double value, UnicodeString& string);
+
+ ChoiceFormat(); // default constructor not implemented
+
+ /**
+ * Construct a new ChoiceFormat with the limits and the corresponding formats
+ * based on the pattern.
+ *
+ * @param newPattern Pattern used to construct object.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered.
+ * @param status Output param to receive success code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ ChoiceFormat(const UnicodeString& newPattern,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ friend class MessageFormat;
+ /**
+ * Each ChoiceFormat divides the range -Inf..+Inf into fCount
+ * intervals. The intervals are:
+ *
+ * 0: fChoiceLimits[0]..fChoiceLimits[1]
+ * 1: fChoiceLimits[1]..fChoiceLimits[2]
+ * ...
+ * fCount-2: fChoiceLimits[fCount-2]..fChoiceLimits[fCount-1]
+ * fCount-1: fChoiceLimits[fCount-1]..+Inf
+ *
+ * Interval 0 is special; during formatting (mapping numbers to
+ * strings), it also contains all numbers less than
+ * fChoiceLimits[0], as well as NaN values.
+ *
+ * Interval i maps to and from string fChoiceFormats[i]. When
+ * parsing (mapping strings to numbers), then intervals map to
+ * their lower limit, that is, interval i maps to fChoiceLimit[i].
+ *
+ * The intervals may be closed, half open, or open. This affects
+ * formatting but does not affect parsing. Interval i is affected
+ * by fClosures[i] and fClosures[i+1]. If fClosures[i]
+ * is FALSE, then the value fChoiceLimits[i] is in interval i.
+ * That is, intervals i and i are:
+ *
+ * i-1: ... x < fChoiceLimits[i]
+ * i: fChoiceLimits[i] <= x ...
+ *
+ * If fClosures[i] is TRUE, then the value fChoiceLimits[i] is
+ * in interval i-1. That is, intervals i-1 and i are:
+ *
+ * i-1: ... x <= fChoiceLimits[i]
+ * i: fChoiceLimits[i] < x ...
+ *
+ * Because of the nature of interval 0, fClosures[0] has no
+ * effect.
+
+ */
+ double* fChoiceLimits;
+ UBool* fClosures;
+ UnicodeString* fChoiceFormats;
+ int32_t fCount;
+};
+
+inline UnicodeString&
+ChoiceFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return NumberFormat::format(obj, appendTo, status);
+}
+
+inline UnicodeString&
+ChoiceFormat::format(double number,
+ UnicodeString& appendTo) const {
+ return NumberFormat::format(number, appendTo);
+}
+
+inline UnicodeString&
+ChoiceFormat::format(int32_t number,
+ UnicodeString& appendTo) const {
+ return NumberFormat::format(number, appendTo);
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CHOICFMT
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/coleitr.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/coleitr.h
new file mode 100644
index 00000000000..4025a41d730
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/coll.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/coll.h
new file mode 100644
index 00000000000..357af13d9b8
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/coll.h
@@ -0,0 +1,1113 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2010, 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;
+
+ /**
+ * Get the current reordering of scripts (if one has been set).
+ * @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 length of the array of the script ordering.
+ * @see ucol_getReorderCodes
+ * @internal
+ */
+ virtual int32_t getReorderCodes(int32_t *dest,
+ int32_t destCapacity,
+ UErrorCode& status) const;
+
+ /**
+ * Set the ordering of scripts for this collator.
+ * @param reorderCodes An array of reorder codes in the new order.
+ * @param reorderCodesLength The length of reorderCodes.
+ * @see ucol_setReorderCodes
+ * @internal
+ */
+ virtual void setReorderCodes(const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ 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.6/i18n/unicode/colldata.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/colldata.h
new file mode 100644
index 00000000000..af465f59208
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/curramt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/curramt.h
new file mode 100644
index 00000000000..c33e6f1f833
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/currpinf.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/currpinf.h
new file mode 100644
index 00000000000..fd9e5da3388
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/currpinf.h
@@ -0,0 +1,259 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, 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
+ */
+ 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.6/i18n/unicode/currunit.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/currunit.h
new file mode 100644
index 00000000000..ecd94110292
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/datefmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/datefmt.h
new file mode 100644
index 00000000000..d21133a83a3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/datefmt.h
@@ -0,0 +1,751 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2010, 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&);
+
+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.6/i18n/unicode/dcfmtsym.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/dcfmtsym.h
new file mode 100644
index 00000000000..dd554c5e1e2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/dcfmtsym.h
@@ -0,0 +1,460 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, 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"
+
+/**
+ * \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
+ };
+
+ /**
+ * Constants for specifying currency spacing
+ * @draft ICU 4.2
+ */
+ enum ECurrencySpacing {
+ kCurrencyMatch,
+ kSurroundingMatch,
+ kInsert,
+ kCurrencySpacingCount
+ };
+
+ /**
+ * 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 : kCurrencyMatch, kSurroundingMatch or kInsert.
+ * @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.2
+ */
+ const UnicodeString& getPatternForCurrencySpacing(ECurrencySpacing type,
+ UBool beforeCurrency,
+ UErrorCode& status) const;
+ /**
+ * Set pattern string for 'CurrencySpacing' that can be applied to
+ * currency format.
+ *
+ * @param type : kCurrencyMatch, kSurroundingMatch or kInsert.
+ * @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.2
+ */
+ void setPatternForCurrencySpacing(ECurrencySpacing 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[kCurrencySpacingCount];
+ UnicodeString currencySpcAfterSym[kCurrencySpacingCount];
+};
+
+// -------------------------------------
+
+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.6/i18n/unicode/decimfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/decimfmt.h
new file mode 100644
index 00000000000..778bf2292da
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/decimfmt.h
@@ -0,0 +1,2310 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, 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 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.
+ *
+ * <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 */
+ // We don't support ROUND_UNNECESSARY
+ };
+
+ /**
+ * Pad position.
+ * @stable ICU 2.4
+ */
+ enum EPadPosition {
+ kPadBeforePrefix,
+ kPadAfterPrefix,
+ kPadBeforeSuffix,
+ kPadAfterSuffix
+ };
+
+ /**
+ * Create a DecimalFormat using the default pattern and symbols
+ * for the default locale. This is a convenient way to obtain a
+ * DecimalFormat when internationalization is not the main concern.
+ * <P>
+ * To obtain standard formats for a given locale, use the factory methods
+ * on NumberFormat such as createInstance. These factories will
+ * return the most appropriate sub-class of NumberFormat for a given
+ * locale.
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat(UErrorCode& status);
+
+ /**
+ * Create a DecimalFormat from the given pattern and the symbols
+ * for the default locale. This is a convenient way to obtain a
+ * DecimalFormat when internationalization is not the main concern.
+ * <P>
+ * To obtain standard formats for a given locale, use the factory methods
+ * on NumberFormat such as createInstance. These factories will
+ * return the most appropriate sub-class of NumberFormat for a given
+ * locale.
+ * @param pattern A non-localized pattern string.
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Create a DecimalFormat from the given pattern and symbols.
+ * Use this constructor when you need to completely customize the
+ * behavior of the format.
+ * <P>
+ * To obtain standard formats for a given
+ * locale, use the factory methods on NumberFormat such as
+ * createInstance or createCurrencyInstance. If you need only minor adjustments
+ * to a standard format, you can modify the format returned by
+ * a NumberFormat factory method.
+ *
+ * @param pattern a non-localized pattern string
+ * @param symbolsToAdopt the set of symbols to be used. The caller should not
+ * delete this object after making this call.
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat( const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UErrorCode& status);
+
+ /**
+ * 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, kNumberStyle etc.
+ * @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,
+ NumberFormat::EStyles 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);
+
+ static int32_t skipRuleWhiteSpace(const UnicodeString& text, int32_t pos);
+
+ static int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos);
+
+ int32_t compareComplexAffix(const UnicodeString& affixPat,
+ const UnicodeString& input,
+ int32_t pos,
+ 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);
+
+ /**
+ * 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.6/i18n/unicode/dtfmtsym.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtfmtsym.h
new file mode 100644
index 00000000000..d858ba9aca1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtfmtsym.h
@@ -0,0 +1,755 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File DTFMTSYM.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 07/21/98 stephen Added getZoneIndex()
+* Changed to match C++ conventions
+********************************************************************************
+*/
+
+#ifndef DTFMTSYM_H
+#define DTFMTSYM_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/uobject.h"
+#include "unicode/locid.h"
+#include "unicode/ures.h"
+
+/**
+ * \file
+ * \brief C++ API: Symbols for formatting dates.
+ */
+
+U_NAMESPACE_BEGIN
+
+/* forward declaration */
+class SimpleDateFormat;
+class Hashtable;
+class ZoneStringFormat;
+class SafeZoneStringFormatPtr;
+
+/**
+ * DateFormatSymbols is a public class for encapsulating localizable date-time
+ * formatting data -- including timezone data. DateFormatSymbols is used by
+ * DateFormat and SimpleDateFormat.
+ * <P>
+ * Rather than first creating a DateFormatSymbols to get a date-time formatter
+ * by using a SimpleDateFormat constructor, clients are encouraged to create a
+ * date-time formatter using the getTimeInstance(), getDateInstance(), or
+ * getDateTimeInstance() method in DateFormat. Each of these methods can return a
+ * date/time formatter initialized with a default format pattern along with the
+ * date-time formatting data for a given or default locale. After a formatter is
+ * created, clients may modify the format pattern using the setPattern function
+ * as so desired. For more information on using these formatter factory
+ * functions, see DateFormat.
+ * <P>
+ * If clients decide to create a date-time formatter with a particular format
+ * pattern and locale, they can do so with new SimpleDateFormat(aPattern,
+ * new DateFormatSymbols(aLocale)). This will load the appropriate date-time
+ * formatting data from the locale.
+ * <P>
+ * DateFormatSymbols objects are clonable. When clients obtain a
+ * DateFormatSymbols object, they can feel free to modify the date-time
+ * formatting data as necessary. For instance, clients can
+ * replace the localized date-time format pattern characters with the ones that
+ * they feel easy to remember. Or they can change the representative cities
+ * originally picked by default to using their favorite ones.
+ * <P>
+ * DateFormatSymbols are not expected to be subclassed. Data for a calendar is
+ * loaded out of resource bundles. The 'type' parameter indicates the type of
+ * calendar, for example, "gregorian" or "japanese". If the type is not gregorian
+ * (or NULL, or an empty string) then the type is appended to the resource name,
+ * for example, 'Eras_japanese' instead of 'Eras'. If the resource 'Eras_japanese' did
+ * not exist (even in root), then this class will fall back to just 'Eras', that is,
+ * Gregorian data. Therefore, the calendar implementor MUST ensure that the root
+ * locale at least contains any resources that are to be particularized for the
+ * calendar type.
+ */
+class U_I18N_API DateFormatSymbols : public UObject {
+public:
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the default locale, in the default calendar (Gregorian).
+ * <P>
+ * NOTE: This constructor will never fail; if it cannot get resource
+ * data for the default locale, it will return a last-resort object
+ * based on hard-coded strings.
+ *
+ * @param status Status code. Failure
+ * results if the resources for the default cannot be
+ * found or cannot be loaded
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols(UErrorCode& status);
+
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the given locale, in the default calendar (Gregorian).
+ *
+ * @param locale Locale to load format data from.
+ * @param status Status code. Failure
+ * results if the resources for the locale cannot be
+ * found or cannot be loaded
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols(const Locale& locale,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the default locale, in the default calendar (Gregorian).
+ * <P>
+ * NOTE: This constructor will never fail; if it cannot get resource
+ * data for the default locale, it will return a last-resort object
+ * based on hard-coded strings.
+ *
+ * @param type Type of calendar (as returned by Calendar::getType).
+ * Will be used to access the correct set of strings.
+ * (NULL or empty string defaults to "gregorian".)
+ * @param status Status code. Failure
+ * results if the resources for the default cannot be
+ * found or cannot be loaded
+ * @internal
+ */
+ DateFormatSymbols(const char *type, UErrorCode& status);
+
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the given locale, in the default calendar (Gregorian).
+ *
+ * @param locale Locale to load format data from.
+ * @param type Type of calendar (as returned by Calendar::getType).
+ * Will be used to access the correct set of strings.
+ * (NULL or empty string defaults to "gregorian".)
+ * @param status Status code. Failure
+ * results if the resources for the locale cannot be
+ * found or cannot be loaded
+ * @internal
+ */
+ DateFormatSymbols(const Locale& locale,
+ const char *type,
+ UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols(const DateFormatSymbols&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols& operator=(const DateFormatSymbols&);
+
+ /**
+ * Destructor. This is nonvirtual because this class is not designed to be
+ * subclassed.
+ * @stable ICU 2.0
+ */
+ virtual ~DateFormatSymbols();
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the DateFormatSymbols object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @stable ICU 2.0
+ */
+ UBool operator==(const DateFormatSymbols& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the DateFormatSymbols object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const DateFormatSymbols& other) const { return !operator==(other); }
+
+ /**
+ * Gets 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.
+ * @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;
+
+ const ZoneStringFormat *fZoneStringFormat;
+ ZoneStringFormat *fZSFLocal; // Local ZoneStringFormat instance
+ SafeZoneStringFormatPtr *fZSFCachePtr; // Cached ZoneStringFormat
+ Locale fZSFLocale; // Locale used for getting ZoneStringFormat
+
+ /**
+ * Pattern string used for localized time zone GMT format. For example, "GMT{0}"
+ */
+ UnicodeString fGmtFormat;
+
+ /**
+ * Pattern strings used for formatting zone offset in a localized time zone GMT string.
+ */
+ UnicodeString *fGmtHourFormats;
+ int32_t fGmtHourFormatsCount;
+
+ enum GMTHourType {
+ GMT_NEGATIVE_HMS = 0,
+ GMT_NEGATIVE_HM,
+ GMT_POSITIVE_HMS,
+ GMT_POSITIVE_HM,
+ GMT_HOUR_COUNT
+ };
+
+ /**
+ * Localized date-time pattern characters. For example: use 'u' as 'y'.
+ */
+ UnicodeString fLocalPatternChars;
+
+private:
+ /** valid/actual locale information
+ * these are always ICU locales, so the length should not be a problem
+ */
+ char validLocale[ULOC_FULLNAME_CAPACITY];
+ char actualLocale[ULOC_FULLNAME_CAPACITY];
+
+ DateFormatSymbols(); // default constructor not implemented
+
+ /**
+ * Called by the constructors to actually load data from the resources
+ *
+ * @param locale The locale to get symbols for.
+ * @param type Calendar Type (as from Calendar::getType())
+ * @param status Input/output parameter, set to success or
+ * failure code upon return.
+ * @param useLastResortData determine if use last resort data
+ */
+ void initializeData(const Locale&, const char *type, UErrorCode& status, UBool useLastResortData = FALSE);
+
+ /**
+ * Copy or alias an array in another object, as appropriate.
+ *
+ * @param dstArray the copy destination array.
+ * @param dstCount fill in with the lenth of 'dstArray'.
+ * @param srcArray the source array to be copied.
+ * @param srcCount the length of items to be copied from the 'srcArray'.
+ */
+ static void assignArray(UnicodeString*& dstArray,
+ int32_t& dstCount,
+ const UnicodeString* srcArray,
+ int32_t srcCount);
+
+ /**
+ * Return true if the given arrays' contents are equal, or if the arrays are
+ * identical (pointers are equal).
+ *
+ * @param array1 one array to be compared with.
+ * @param array2 another array to be compared with.
+ * @param count the length of items to be copied.
+ * @return true if the given arrays' contents are equal, or if the arrays are
+ * identical (pointers are equal).
+ */
+ static UBool arrayCompare(const UnicodeString* array1,
+ const UnicodeString* array2,
+ int32_t count);
+
+ /**
+ * Create a copy, in fZoneStrings, of the given zone strings array. The
+ * member variables fZoneStringsRowCount and fZoneStringsColCount should be
+ * set already by the caller.
+ */
+ void createZoneStrings(const UnicodeString *const * otherStrings);
+
+ /**
+ * Delete all the storage owned by this object.
+ */
+ void dispose(void);
+
+ /**
+ * Copy all of the other's data to this.
+ * @param other the object to be copied.
+ */
+ void copyData(const DateFormatSymbols& other);
+
+
+ /**
+ * Returns a ZoneStringFormat, used only by SimpleDateFormat for now.
+ */
+ const ZoneStringFormat* getZoneStringFormat(void) const;
+
+ /**
+ * Create a ZoneStringFormat by locale if not yet availble
+ */
+ void initZoneStringFormat(void);
+
+ /**
+ * Create zone strings array by locale if not yet available
+ */
+ void initZoneStringsArray(void);
+
+ /**
+ * Delete just the zone strings.
+ */
+ void disposeZoneStrings(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DTFMTSYM
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/dtitvfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtitvfmt.h
new file mode 100644
index 00000000000..750454f703f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtitvfmt.h
@@ -0,0 +1,970 @@
+/********************************************************************************
+* Copyright (C) 2008-2010, 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 interval format 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;
+
+ /**
+ * 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 dtitvinf 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.6/i18n/unicode/dtitvinf.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtitvinf.h
new file mode 100644
index 00000000000..f6513a2147b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/dtptngen.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtptngen.h
new file mode 100644
index 00000000000..1a0f70bc844
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/dtrule.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/dtrule.h
new file mode 100644
index 00000000000..cb526a152ce
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/fieldpos.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/fieldpos.h
new file mode 100644
index 00000000000..38a9576e782
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/fmtable.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/fmtable.h
new file mode 100644
index 00000000000..0834037ebf4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/fmtable.h
@@ -0,0 +1,673 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, 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.6/i18n/unicode/format.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/format.h
new file mode 100644
index 00000000000..5651c9e44e5
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/fpositer.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/fpositer.h
new file mode 100644
index 00000000000..ecaa77728ac
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/gregocal.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/gregocal.h
new file mode 100644
index 00000000000..c17b6fe97d6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/gregocal.h
@@ -0,0 +1,823 @@
+/*
+* Copyright (C) 1997-2009, 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;
+
+protected:
+
+ /**
+ * (Overrides Calendar) Converts GMT as milliseconds to time field values.
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @stable ICU 2.0
+ */
+
+ private:
+ GregorianCalendar(); // default constructor not implemented
+
+ protected:
+ /**
+ * Return the ERA. We need a special method for this because the
+ * default ERA is AD, but a zero (unset) ERA is BC.
+ * @return the ERA.
+ * @internal
+ */
+ virtual int32_t internalGetEra() const;
+
+ /**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year. Subclasses should override
+ * this method to implement their calendar system.
+ * @param eyear the extended year
+ * @param month the zero-based month, or 0 if useMonth is false
+ * @param useMonth if false, compute the day before the first day of
+ * the given year, otherwise, compute the day before the first day of
+ * the given month
+ * @return the Julian day number of the day before the first
+ * day of the given month and year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
+ UBool useMonth) const;
+
+ /**
+ * Subclasses may override this. This method calls
+ * handleGetMonthLength() to obtain the calendar-specific month
+ * length.
+ * @param bestField which field to use to calculate the date
+ * @return julian day specified by calendar fields.
+ * @internal
+ */
+ virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField) ;
+
+ /**
+ * Return the number of days in the given month of the given extended
+ * year of this calendar system. Subclasses should override this
+ * method if they can provide a more correct or more efficient
+ * implementation than the default implementation in Calendar.
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+
+ /**
+ * Return the number of days in the given extended year of this
+ * calendar system. Subclasses should override this method if they can
+ * provide a more correct or more efficient implementation than the
+ * default implementation in Calendar.
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleGetYearLength(int32_t eyear) const;
+
+ /**
+ * return the length of the given month.
+ * @param month the given month.
+ * @return the length of the given month.
+ * @internal
+ */
+ virtual int32_t monthLength(int32_t month) const;
+
+ /**
+ * return the length of the month according to the given year.
+ * @param month the given month.
+ * @param year the given year.
+ * @return the length of the month
+ * @internal
+ */
+ virtual int32_t monthLength(int32_t month, int32_t year) const;
+
+ /**
+ * return the length of the given year.
+ * @param year the given year.
+ * @return the length of the given year.
+ * @internal
+ */
+ int32_t yearLength(int32_t year) const;
+
+ /**
+ * return the length of the year field.
+ * @return the length of the year field
+ * @internal
+ */
+ int32_t yearLength(void) const;
+
+ /**
+ * After adjustments such as add(MONTH), add(YEAR), we don't want the
+ * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
+ * 3, we want it to go to Feb 28. Adjustments which might run into this
+ * problem call this method to retain the proper month.
+ * @internal
+ */
+ void pinDayOfMonth(void);
+
+ /**
+ * Return the day number with respect to the epoch. January 1, 1970 (Gregorian)
+ * is day zero.
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return the day number with respect to the epoch.
+ * @internal
+ */
+ virtual UDate getEpochDay(UErrorCode& status);
+
+ /**
+ * Subclass API for defining limits of different types.
+ * Subclasses must implement this method to return limits for the
+ * following fields:
+ *
+ * <pre>UCAL_ERA
+ * UCAL_YEAR
+ * UCAL_MONTH
+ * UCAL_WEEK_OF_YEAR
+ * UCAL_WEEK_OF_MONTH
+ * UCAL_DATE (DAY_OF_MONTH on Java)
+ * UCAL_DAY_OF_YEAR
+ * UCAL_DAY_OF_WEEK_IN_MONTH
+ * UCAL_YEAR_WOY
+ * UCAL_EXTENDED_YEAR</pre>
+ *
+ * @param field one of the above field numbers
+ * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
+ * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * Subclasses may override this to convert from week fields
+ * (YEAR_WOY and WEEK_OF_YEAR) to an extended year in the case
+ * where YEAR, EXTENDED_YEAR are not set.
+ * The Gregorian implementation assumes a yearWoy in gregorian format, according to the current era.
+ * @return the extended year, UCAL_EXTENDED_YEAR
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy);
+
+
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * <p>The GregorianCalendar implementation implements
+ * a calendar with the specified Julian/Gregorian cutover date.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ private:
+ /**
+ * Compute the julian day number of the given year.
+ * @param isGregorian if true, using Gregorian calendar, otherwise using Julian calendar
+ * @param year the given year.
+ * @param isLeap true if the year is a leap year.
+ * @return
+ */
+ static double computeJulianDayOfYear(UBool isGregorian, int32_t year,
+ UBool& isLeap);
+
+ /**
+ * Validates the values of the set time fields. True if they're all valid.
+ * @return True if the set time fields are all valid.
+ */
+ UBool validateFields(void) const;
+
+ /**
+ * Validates the value of the given time field. True if it's valid.
+ */
+ UBool boundsCheck(int32_t value, UCalendarDateFields field) const;
+
+ /**
+ * Return the pseudo-time-stamp for two fields, given their
+ * individual pseudo-time-stamps. If either of the fields
+ * is unset, then the aggregate is unset. Otherwise, the
+ * aggregate is the later of the two stamps.
+ * @param stamp_a One given field.
+ * @param stamp_b Another given field.
+ * @return the pseudo-time-stamp for two fields
+ */
+ int32_t aggregateStamp(int32_t stamp_a, int32_t stamp_b);
+
+ /**
+ * The point at which the Gregorian calendar rules are used, measured in
+ * milliseconds from the standard epoch. Default is October 15, 1582
+ * (Gregorian) 00:00:00 UTC, that is, October 4, 1582 (Julian) is followed
+ * by October 15, 1582 (Gregorian). This corresponds to Julian day number
+ * 2299161. This is measured from the standard epoch, not in Julian Days.
+ * @internal
+ */
+ UDate fGregorianCutover;
+
+ /**
+ * Julian day number of the Gregorian cutover
+ */
+ int32_t fCutoverJulianDay;
+
+ /**
+ * Midnight, local time (using this Calendar's TimeZone) at or before the
+ * gregorianCutover. This is a pure date value with no time of day or
+ * timezone component.
+ */
+ UDate fNormalizedGregorianCutover;// = gregorianCutover;
+
+ /**
+ * The year of the gregorianCutover, with 0 representing
+ * 1 BC, -1 representing 2 BC, etc.
+ */
+ int32_t fGregorianCutoverYear;// = 1582;
+
+ /**
+ * The year of the gregorianCutover, with 0 representing
+ * 1 BC, -1 representing 2 BC, etc.
+ */
+ int32_t fGregorianCutoverJulianDay;// = 2299161;
+
+ /**
+ * Converts time as milliseconds to Julian date. The Julian date used here is not a
+ * true Julian date, since it is measured from midnight, not noon.
+ *
+ * @param millis The given milliseconds.
+ * @return The Julian date number.
+ */
+ static double millisToJulianDay(UDate millis);
+
+ /**
+ * Converts Julian date to time as milliseconds. The Julian date used here is not a
+ * true Julian date, since it is measured from midnight, not noon.
+ *
+ * @param julian The given Julian date number.
+ * @return Time as milliseconds.
+ */
+ static UDate julianDayToMillis(double julian);
+
+ /**
+ * Used by handleComputeJulianDay() and handleComputeMonthStart().
+ * Temporary field indicating whether the calendar is currently Gregorian as opposed to Julian.
+ */
+ UBool fIsGregorian;
+
+ /**
+ * Used by handleComputeJulianDay() and handleComputeMonthStart().
+ * Temporary field indicating that the sense of the gregorian cutover should be inverted
+ * to handle certain calculations on and around the cutover date.
+ */
+ UBool fInvertGregorian;
+
+
+ public: // internal implementation
+
+ /**
+ * @internal
+ * @return TRUE if this calendar has the notion of a default century
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * @internal
+ * @return the start of the default century
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * @internal
+ * @return the beginning year of the default century
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private:
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * Default value that indicates the UDate of the beginning of the system default century
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ * @return the beginning date of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ * @return the first year of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years are considered
+ * to fall within so that its start date is 80 years before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _GREGOCAL
+//eof
+
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/locdspnm.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/locdspnm.h
new file mode 100644
index 00000000000..647b062da02
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/locdspnm.h
@@ -0,0 +1,188 @@
+/*
+******************************************************************************
+* Copyright (C) 2010, 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 #getInstance}.
+ * @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.6/i18n/unicode/measfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/measfmt.h
new file mode 100644
index 00000000000..a5af55e9d53
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/measunit.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/measunit.h
new file mode 100644
index 00000000000..9a210e65957
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/measure.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/measure.h
new file mode 100644
index 00000000000..6b7a0497b47
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/msgfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/msgfmt.h
new file mode 100644
index 00000000000..58c74f1cb1b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/msgfmt.h
@@ -0,0 +1,961 @@
+/*
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+********************************************************************************
+*
+* File MSGFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation.
+* 07/22/98 stephen Removed operator!= (defined in Format)
+* 08/19/2002 srl Removing Javaisms
+*******************************************************************************/
+
+#ifndef MSGFMT_H
+#define MSGFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Formats messages in a language-neutral way.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/locid.h"
+#include "unicode/parseerr.h"
+#include "unicode/uchar.h"
+
+U_NAMESPACE_BEGIN
+
+class NumberFormat;
+class DateFormat;
+
+/**
+ *
+ * MessageFormat produces concatenated messages in a language-neutral
+ * way. Use this whenever concatenating strings that are displayed to
+ * end users.
+ *
+ * <P>A MessageFormat contains an array of <EM>subformats</EM> arranged
+ * within a <EM>template string</EM>. Together, the subformats and
+ * template string determine how the MessageFormat will operate during
+ * formatting and parsing.
+ *
+ * <P>Typically, both the subformats and the template string are
+ * specified at once in a <EM>pattern</EM>. By using different
+ * patterns for different locales, messages may be localized.
+ *
+ * <P>When formatting, MessageFormat takes an array of arguments
+ * and produces a user-readable string. Each argument is a
+ * Formattable object; they may be passed in in an array, or as a
+ * single Formattable object which itself contains an array. Each
+ * argument is matched up with its corresponding subformat, which then
+ * formats it into a string. The resulting strings are then assembled
+ * within the string template of the MessageFormat to produce the
+ * final output string.
+ *
+ * <p><strong>Note:</strong>
+ * In ICU 4.0 MessageFormat supports named arguments. If a named argument
+ * is used, all arguments must be named. Names start with a character in
+ * <code>UCHAR_ID_START</code> and continue with characters in
+ * <code>UCHARID_CONTINUE</code>, in particular they do not start with a digit.
+ * If named arguments are used, {@link #usesNamedArguments()} will return true.
+ *
+ * <p>The other new methods supporting named arguments are
+ * {@link #getFormatNames(UErrorCode& status)},
+ * {@link #getFormat(const UnicodeString& formatName, UErrorCode& status)}
+ * {@link #setFormat(const UnicodeString& formatName, const Format& format, UErrorCode& status)},
+ * {@link #adoptFormat(const UnicodeString& formatName, Format* formatToAdopt, UErrorCode& status)},
+ * {@link #format(const UnicodeString* argumentNames, const Formattable* arguments,
+ * int32_t count, UnicodeString& appendTo,UErrorCode& status)}.
+ * These methods are all compatible with patterns that do not used named arguments--
+ * in these cases the keys in the input or output use <code>UnicodeString</code>s
+ * that name the argument indices, e.g. "0", "1", "2"... etc.
+ *
+ * <p>If this format uses named arguments, certain methods that take or
+ * return arrays do not perform any action, since it is not possible to
+ * identify positions in an array using a name. Of these methods,
+ * UErrorCode is set to U_ILLEGAL_ARGUMENT_ERROR by format, and to
+ * U_ARGUMENT_TYPE_MISMATCH by parse.
+ * These methods are
+ * {@link #adoptFormats(Format** formatsToAdopt, int32_t count)},
+ * {@link #setFormats(const Format** newFormats,int32_t count)},
+ * {@link #adoptFormat(int32_t n, Format *newFormat)},
+ * {@link #setFormat(int32_t n, Format& newFormat)},
+ * {@link #format(const Formattable* source, int32_t count, UnicodeString& appendTo, FieldPosition& ignore, UErrorCode& success)},
+ * {@link #format(const UnicodeString& pattern,const Formattable* arguments,int32_t cnt,UnicodeString& appendTo,UErrorCode& success)},
+ * {@link #format(const Formattable& source, UnicodeString& appendTo, FieldPosition& ignore, UErrorCode& success)},
+ * {@link #format(const Formattable* arguments, int32_t cnt, UnicodeString& appendTo, FieldPosition& status, int32_t recursionProtection,UErrorCode& success)},
+ * {@link #parse(const UnicodeString& source, ParsePosition& pos, int32_t& count)},
+ * {@link #parse(const UnicodeString& source, int32_t& cnt, UErrorCode& status)}
+ *
+ * <P>
+ * During parsing, an input string is matched against the string
+ * template of the MessageFormat to produce an array of Formattable
+ * objects. Plain text of the template string is matched directly
+ * against input text. At each position in the template string where
+ * a subformat is located, the subformat is called to parse the
+ * corresponding segment of input text to produce an output argument.
+ * In this way, an array of arguments is created which together
+ * constitute the parse result.
+ * <P>
+ * Parsing may fail or produce unexpected results in a number of
+ * circumstances.
+ * <UL>
+ * <LI>If one of the arguments does not occur in the pattern, it
+ * will be returned as a default Formattable.
+ * <LI>If the format of an argument loses information, such as with
+ * a choice format where a large number formats to "many", then the
+ * parse may not correspond to the originally formatted argument.
+ * <LI>MessageFormat does not handle ChoiceFormat recursion during
+ * parsing; such parses will fail.
+ * <LI>Parsing will not always find a match (or the correct match) if
+ * some part of the parse is ambiguous. For example, if the pattern
+ * "{1},{2}" is used with the string arguments {"a,b", "c"}, it will
+ * format as "a,b,c". When the result is parsed, it will return {"a",
+ * "b,c"}.
+ * <LI>If a single argument is formatted more than once in the string,
+ * then the rightmost subformat in the pattern string will produce the
+ * parse result; prior subformats with the same argument index will
+ * have no effect.
+ * </UL>
+ * Here are some examples of usage:
+ * <P>
+ * Example 1:
+ * <pre>
+ * \code
+ * UErrorCode success = U_ZERO_ERROR;
+ * GregorianCalendar cal(success);
+ * Formattable arguments[] = {
+ * 7L,
+ * Formattable( (Date) cal.getTime(success), Formattable::kIsDate),
+ * "a disturbance in the Force"
+ * };
+ *
+ * UnicodeString result;
+ * MessageFormat::format(
+ * "At {1,time} on {1,date}, there was {2} on planet {0,number}.",
+ * arguments, 3, result, success );
+ *
+ * cout << "result: " << result << endl;
+ * //<output>: At 4:34:20 PM on 23-Mar-98, there was a disturbance
+ * // in the Force on planet 7.
+ * \endcode
+ * </pre>
+ * Typically, the message format will come from resources, and the
+ * arguments will be dynamically set at runtime.
+ * <P>
+ * Example 2:
+ * <pre>
+ * \code
+ * success = U_ZERO_ERROR;
+ * Formattable testArgs[] = {3L, "MyDisk"};
+ *
+ * MessageFormat form(
+ * "The disk \"{1}\" contains {0} file(s).", success );
+ *
+ * UnicodeString string;
+ * FieldPosition fpos = 0;
+ * cout << "format: " << form.format(testArgs, 2, string, fpos, success ) << endl;
+ *
+ * // output, with different testArgs:
+ * // output: The disk "MyDisk" contains 0 file(s).
+ * // output: The disk "MyDisk" contains 1 file(s).
+ * // output: The disk "MyDisk" contains 1,273 file(s).
+ * \endcode
+ * </pre>
+ *
+ * The pattern is of the following form. Legend:
+ * <pre>
+ * \code
+ * {optional item}
+ * (group that may be repeated)*
+ * \endcode
+ * </pre>
+ * Do not confuse optional items with items inside quoted braces, such
+ * as this: "{". Quoted braces are literals.
+ * <pre>
+ * \code
+ * messageFormatPattern := string ( "{" messageFormatElement "}" string )*
+ *
+ * messageFormatElement := argumentIndex | argumentName { "," elementFormat }
+ *
+ * elementFormat := "time" { "," datetimeStyle }
+ * | "date" { "," datetimeStyle }
+ * | "number" { "," numberStyle }
+ * | "choice" "," choiceStyle
+ * | "spellout" { "," spelloutStyle }
+ * | "ordinal" { "," spelloutStyle }
+ * | "duration" { "," spelloutStyle }
+ * | "plural" "," pluralStyle
+ * | "select" "," selectStyle
+ *
+ * datetimeStyle := "short"
+ * | "medium"
+ * | "long"
+ * | "full"
+ * | dateFormatPattern
+ *
+ * numberStyle := "currency"
+ * | "percent"
+ * | "integer"
+ * | numberFormatPattern
+ *
+ * choiceStyle := choiceFormatPattern
+ *
+ * pluralStyle := pluralFormatPattern
+ *
+ * selectStyle := selectFormatPattern
+ *
+ * spelloutStyle := ruleSetName
+ * \endcode
+ * </pre>
+ * If there is no elementFormat, then the argument must be a string,
+ * which is substituted. If there is no dateTimeStyle or numberStyle,
+ * then the default format is used (e.g. NumberFormat::createInstance(),
+ * DateFormat::createTimeInstance(DateFormat::kDefault, ...) or
+ * DateFormat::createDateInstance(DateFormat::kDefault, ...). For
+ * a RuleBasedNumberFormat, if there is no ruleSetName, the default
+ * rule set is used. For a ChoiceFormat or PluralFormat or SelectFormat, the pattern
+ * must always be specified, since there is no default.
+ * <P>
+ * In strings, single quotes can be used to quote syntax characters.
+ * A literal single quote is represented by '', both within and outside
+ * of single-quoted segments. Inside a
+ * messageFormatElement, quotes are <EM>not</EM> removed. For example,
+ * {1,number,$'#',##} will produce a number format with the pound-sign
+ * quoted, with a result such as: "$#31,45".
+ * <P>
+ * If a pattern is used, then unquoted braces in the pattern, if any,
+ * must match: that is, "ab {0} de" and "ab '}' de" are ok, but "ab
+ * {0'}' de" and "ab } de" are not.
+ * <p>
+ * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
+ * format patterns unfortunately have shown to be somewhat confusing.
+ * In particular, it isn't always obvious to localizers whether single
+ * quotes need to be doubled or not. Make sure to inform localizers about
+ * the rules, and tell them (for example, by using comments in resource
+ * bundle source files) which strings will be processed by MessageFormat.
+ * Note that localizers may need to use single quotes in translated
+ * strings where the original version doesn't have them.
+ * <br>Note also that the simplest way to avoid the problem is to
+ * use the real apostrophe (single quote) character U+2019 (') for
+ * human-readable text, and to use the ASCII apostrophe (U+0027 ' )
+ * only in program syntax, like quoting in MessageFormat.
+ * See the annotations for U+0027 Apostrophe in The Unicode Standard.</p>
+ * </dl>
+ * <P>
+ * The argumentIndex is a non-negative integer, which corresponds to the
+ * index of the arguments presented in an array to be formatted. The
+ * first argument has argumentIndex 0.
+ * <P>
+ * It is acceptable to have unused arguments in the array. With missing
+ * arguments, or arguments that are not of the right class for the
+ * specified format, a failing UErrorCode result is set.
+ * <P>
+ * <strong>Creating internationalized messages that include plural forms, you
+ * can use a PluralFormat:</strong>
+ * <pre>
+ * \code
+ * UErrorCode err = U_ZERO_ERROR;
+ * UnicodeString t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste.");
+ * MessageFormat* msgFmt = new MessageFormat(t1, Locale("fr"), err);
+ * if (U_FAILURE(err)) {
+ * return err;
+ * }
+ *
+ * Formattable args1[] = {(int32_t)0};
+ * Formattable args2[] = {(int32_t)3};
+ * FieldPosition ignore(FieldPosition::DONT_CARE);
+ * UnicodeString result;
+ * msgFmt->format(args1, 1, result, ignore, status);
+ * cout << result << endl;
+ * result.remove();
+ * msgFmt->format(args2, 1, result, ignore, status);
+ * cout << result << endl;
+ *
+ * // output, with different args
+ * // output: C'est 0,0 fichier dans la liste.
+ * // output: Ce sont 3 fichiers dans la liste."
+ * \endcode
+ * </pre>
+ * Please check PluralFormat and PluralRules for details.
+ * </P>
+ */
+class U_I18N_API MessageFormat : public Format {
+public:
+ /**
+ * Enum type for kMaxFormat.
+ * @obsolete ICU 3.0. The 10-argument limit was removed as of ICU 2.6,
+ * rendering this enum type obsolete.
+ */
+ enum EFormatNumber {
+ /**
+ * The maximum number of arguments.
+ * @obsolete ICU 3.0. The 10-argument limit was removed as of ICU 2.6,
+ * rendering this constant obsolete.
+ */
+ kMaxFormat = 10
+ };
+
+ /**
+ * Constructs a new MessageFormat using the given pattern and the
+ * default locale.
+ *
+ * @param pattern Pattern used to construct object.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const UnicodeString& pattern,
+ UErrorCode &status);
+
+ /**
+ * Constructs a new MessageFormat using the given pattern and locale.
+ * @param pattern Pattern used to construct object.
+ * @param newLocale The locale to use for formatting dates and numbers.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UErrorCode& status);
+ /**
+ * Constructs a new MessageFormat using the given pattern and locale.
+ * @param pattern Pattern used to construct object.
+ * @param newLocale The locale to use for formatting dates and numbers.
+ * @param parseError Struct to recieve information on position
+ * of error within the pattern.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Constructs a new MessageFormat from an existing one.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const MessageFormat&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ const MessageFormat& operator=(const MessageFormat&);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~MessageFormat();
+
+ /**
+ * Clones this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ * @stable ICU 2.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Returns true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Sets the locale. This locale is used for fetching default number or date
+ * format information.
+ * @param theLocale the new locale value to be set.
+ * @stable ICU 2.0
+ */
+ virtual void setLocale(const Locale& theLocale);
+
+ /**
+ * Gets the locale. This locale is used for fetching default number or date
+ * format information.
+ * @return the locale of the object.
+ * @stable ICU 2.0
+ */
+ virtual const Locale& getLocale(void) const;
+
+ /**
+ * Applies the given pattern string to this message format.
+ *
+ * @param pattern The pattern to be applied.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+ /**
+ * Applies the given pattern string to this message format.
+ *
+ * @param pattern The pattern to be applied.
+ * @param parseError Struct to recieve information on position
+ * of error within pattern.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Returns a pattern that can be used to recreate this object.
+ *
+ * @param appendTo Output parameter to receive the pattern.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString& appendTo) const;
+
+ /**
+ * Sets subformats.
+ * See the class description about format numbering.
+ * The caller should not delete the Format objects after this call.
+ * <EM>The array formatsToAdopt is not itself adopted.</EM> Its
+ * ownership is retained by the caller. If the call fails because
+ * memory cannot be allocated, then the formats will be deleted
+ * by this method, and this object will remain unchanged.
+ *
+ * <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 caller's resposibility
+ * 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);
+
+private:
+
+ Locale fLocale;
+ UnicodeString fPattern;
+ Format** formatAliases; // see getFormats
+ int32_t formatAliasesCapacity;
+ UProperty idStart;
+ UProperty idContinue;
+
+ MessageFormat(); // default constructor not implemented
+
+ /*
+ * A structure representing one subformat of this MessageFormat.
+ * Each subformat has a Format object, an offset into the plain
+ * pattern text fPattern, and an argument number. The argument
+ * number corresponds to the array of arguments to be formatted.
+ * @internal
+ */
+ class Subformat;
+
+ /**
+ * A MessageFormat contains an array of subformats. This array
+ * needs to grow dynamically if the MessageFormat is modified.
+ */
+ Subformat* subformats;
+ int32_t subformatCount;
+ int32_t subformatCapacity;
+
+ /**
+ * A MessageFormat formats an array of arguments. Each argument
+ * has an expected type, based on the pattern. For example, if
+ * the pattern contains the subformat "{3,number,integer}", then
+ * we expect argument 3 to have type Formattable::kLong. This
+ * array needs to grow dynamically if the MessageFormat is
+ * modified.
+ */
+ Formattable::Type* argTypes;
+ int32_t argTypeCount;
+ int32_t argTypeCapacity;
+
+ /**
+ * Is true iff all argument names are non-negative numbers.
+ *
+ */
+ UBool isArgNumeric;
+
+ // Variable-size array management
+ UBool allocateSubformats(int32_t capacity);
+ UBool allocateArgTypes(int32_t capacity);
+
+ /**
+ * Default Format objects used when no format is specified and a
+ * numeric or date argument is formatted. These are volatile
+ * cache objects maintained only for performance. They do not
+ * participate in operator=(), copy constructor(), nor
+ * operator==().
+ */
+ NumberFormat* defaultNumberFormat;
+ DateFormat* defaultDateFormat;
+
+ /**
+ * Method to retrieve default formats (or NULL on failure).
+ * These are semantically const, but may modify *this.
+ */
+ const NumberFormat* getDefaultNumberFormat(UErrorCode&) const;
+ const DateFormat* getDefaultDateFormat(UErrorCode&) const;
+
+ /**
+ * Finds the word s, in the keyword list and returns the located index.
+ * @param s the keyword to be searched for.
+ * @param list the list of keywords to be searched with.
+ * @return the index of the list which matches the keyword s.
+ */
+ static int32_t findKeyword( const UnicodeString& s,
+ const UChar * const *list);
+
+ /**
+ * Formats the array of arguments and copies the result into the
+ * result buffer, updates the field position.
+ *
+ * @param arguments The formattable objects array.
+ * @param cnt The array count.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Field position status.
+ * @param recursionProtection
+ * Initially zero. Bits 0..9 are used to indicate
+ * that a parameter has already been seen, to
+ * avoid recursion. Currently unused.
+ * @param success The error code status.
+ * @return Reference to 'appendTo' parameter.
+ */
+ UnicodeString& format( const Formattable* arguments,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& status,
+ int32_t recursionProtection,
+ UErrorCode& success) const;
+
+ UnicodeString& format( const Formattable* arguments,
+ const UnicodeString *argumentNames,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& status,
+ int32_t recursionProtection,
+ UErrorCode& success) const;
+
+ void makeFormat(int32_t offsetNumber,
+ UnicodeString* segments,
+ UParseError& parseError,
+ UErrorCode& success);
+
+ /**
+ * Convenience method that ought to be in NumberFormat
+ */
+ NumberFormat* createIntegerFormat(const Locale& locale, UErrorCode& status) const;
+
+ /**
+ * Checks the range of the source text to quote the special
+ * characters, { and ' and copy to target buffer.
+ * @param source
+ * @param start the text offset to start the process of in the source string
+ * @param end the text offset to end the process of in the source string
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ */
+ static void copyAndFixQuotes(const UnicodeString& appendTo, int32_t start, int32_t end, UnicodeString& target);
+
+ /**
+ * Returns array of argument types in the parsed pattern
+ * for use in C API. Only for the use of umsg_vformat(). Not
+ * for public consumption.
+ * @param listCount Output parameter to receive the size of array
+ * @return The array of formattable types in the pattern
+ * @internal
+ */
+ const Formattable::Type* getArgTypeList(int32_t& listCount) const {
+ listCount = argTypeCount;
+ return argTypes;
+ }
+
+ /**
+ * Returns FALSE if the argument name is not legal.
+ * @param argName argument name.
+ * @return TRUE if the argument name is legal, otherwise return FALSE.
+ */
+ UBool isLegalArgName(const UnicodeString& argName) 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.6/i18n/unicode/numfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/numfmt.h
new file mode 100644
index 00000000000..63914ca4f1a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/numfmt.h
@@ -0,0 +1,1051 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2010, 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"
+
+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:
+
+ /**
+ * Constants for various number format styles.
+ * kNumberStyle specifies a normal number style of format.
+ * kCurrencyStyle specifies a currency format using currency symbol name,
+ * such as in "$1.00".
+ * kPercentStyle specifies a style of format to display percent.
+ * kScientificStyle specifies a style of format to display scientific number.
+ * kISOCurrencyStyle specifies a currency format using ISO currency code,
+ * such as in "USD1.00".
+ * kPluralCurrencyStyle specifies a currency format using currency plural
+ * names, such as in "1.00 US dollar" and "3.00 US dollars".
+ * @draft ICU 4.2
+ */
+ enum EStyles {
+ kNumberStyle,
+ kCurrencyStyle,
+ kPercentStyle,
+ kScientificStyle,
+ kIsoCurrencyStyle,
+ kPluralCurrencyStyle,
+ kStyleCount // ALWAYS LAST ENUM: number of styles
+ };
+
+ /**
+ * 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);
+
+ /**
+ * 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 choice the given style.
+ * @param success Output param filled with success/failure status.
+ * @return A new NumberFormat instance.
+ * @draft ICU 4.2
+ */
+ static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
+
+
+ /**
+ * 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:
+
+ /**
+ * Creates the specified decimal format style of the desired locale.
+ * @param desiredLocale the given locale.
+ * @param choice the given style.
+ * @param success Output param filled with success/failure status.
+ * @return A new NumberFormat instance.
+ */
+ static NumberFormat* makeInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
+
+ UBool fGroupingUsed;
+ int32_t fMaxIntegerDigits;
+ int32_t fMinIntegerDigits;
+ int32_t fMaxFractionDigits;
+ int32_t fMinFractionDigits;
+ UBool fParseIntegerOnly;
+
+ // ISO currency code
+ UChar fCurrency[4];
+
+ friend class ICUNumberFormatFactory; // access to makeInstance, EStyles
+ friend class ICUNumberFormatService;
+};
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * A NumberFormatFactory is used to register new number formats. The factory
+ * should be able to create any of the predefined formats for each locale it
+ * supports. When registered, the locales it supports extend or override the
+ * locale already supported by ICU.
+ *
+ * @stable ICU 2.6
+ */
+class U_I18N_API NumberFormatFactory : public UObject {
+public:
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~NumberFormatFactory();
+
+ /**
+ * Return true if this factory will be visible. Default is true.
+ * If not visible, the locales supported by this factory will not
+ * be listed by getAvailableLocales.
+ * @stable ICU 2.6
+ */
+ virtual UBool visible(void) const = 0;
+
+ /**
+ * Return the locale names directly supported by this factory. The number of names
+ * is returned in count;
+ * @stable ICU 2.6
+ */
+ virtual const UnicodeString * getSupportedIDs(int32_t &count, UErrorCode& status) const = 0;
+
+ /**
+ * Return a number format of the appropriate type. If the locale
+ * is not supported, return null. If the locale is supported, but
+ * the type is not provided by this service, return null. Otherwise
+ * return an appropriate instance of NumberFormat.
+ * @stable ICU 2.6
+ */
+ virtual NumberFormat* createFormat(const Locale& loc, UNumberFormatStyle formatType) = 0;
+};
+
+/**
+ * A NumberFormatFactory that supports a single locale. It can be visible or invisible.
+ * @stable ICU 2.6
+ */
+class U_I18N_API SimpleNumberFormatFactory : public NumberFormatFactory {
+protected:
+ /**
+ * True if the locale supported by this factory is visible.
+ * @stable ICU 2.6
+ */
+ const UBool _visible;
+
+ /**
+ * The locale supported by this factory, as a UnicodeString.
+ * @stable ICU 2.6
+ */
+ UnicodeString _id;
+
+public:
+ /**
+ * @stable ICU 2.6
+ */
+ SimpleNumberFormatFactory(const Locale& locale, UBool visible = TRUE);
+
+ /**
+ * @stable ICU 3.0
+ */
+ virtual ~SimpleNumberFormatFactory();
+
+ /**
+ * @stable ICU 2.6
+ */
+ virtual UBool visible(void) const;
+
+ /**
+ * @stable ICU 2.6
+ */
+ virtual const UnicodeString * getSupportedIDs(int32_t &count, UErrorCode& status) const;
+};
+#endif /* #if !UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+
+inline UBool
+NumberFormat::isParseIntegerOnly() const
+{
+ return fParseIntegerOnly;
+}
+
+inline UnicodeString&
+NumberFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return Format::format(obj, appendTo, status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _NUMFMT
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/numsys.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/numsys.h
new file mode 100644
index 00000000000..4fed0029703
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/plurfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/plurfmt.h
new file mode 100644
index 00000000000..35a6172bbb1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/plurfmt.h
@@ -0,0 +1,549 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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/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 users 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., paucal 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 locales. Thus, the programmer
+ * need not worry about the plural cases of a language. On the flip side,
+ * the localizer does not have to specify the plural cases; he 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 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>
+ * 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
+ * used locale. The pattern is a sequence of
+ * <code><i>caseKeyword</i>{<i>message</i>}</code> clauses, separated by white
+ * space characters. Each clause assigns the message <code><i>message</i></code>
+ * to the plural case identified by <code><i>caseKeyword</i></code>.
+ * </p><p>
+ * There are 6 predefined casekeyword in 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 the plural
+ * rules of the <code>PluralFormat</code> object do not contain a plural case
+ * identified by <code><i>caseKeyword</i></code>, U_DEFAULT_KEYWORD_MISSING
+ * will be set to status.
+ * 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. If you specify more than one message for the same plural case,
+ * U_DUPLICATE_KEYWORD will be set to status.
+ * <br>
+ * Spaces between <code><i>caseKeyword</i></code> and
+ * <code><i>message</i></code> will be ignored; spaces within
+ * <code><i>message</i></code> will be preserved.
+ * </p><p>
+ * The message text for a particular plural case may contain other message
+ * format patterns. <code>PluralFormat</code> preserves these so that you
+ * can use the strings produced by <code>PluralFormat</code> with other
+ * formatters. If you are using <code>PluralFormat</code> inside a
+ * <code>MessageFormat</code> pattern, <code>MessageFormat</code> will
+ * automatically evaluate the resulting format pattern.<br>
+ * Thus, curly braces (<code>{</code>, <code>}</code>) are <i>only</i> allowed
+ * in message texts to define a nested format pattern.<br>
+ * The pound sign (<code>#</code>) will be interpreted as the number placeholder
+ * in the message text, if it is not contained in curly braces (to preserve
+ * <code>NumberFormat</code> patterns). <code>PluralFormat</code> will
+ * replace each of those pound signs by the number passed to the
+ * <code>format()</code> method. It will be formatted using a
+ * <code>NumberFormat</code> for the <code>PluralFormat</code>'s locale. If you
+ * need special number formatting, you have to explicitly specify a
+ * <code>NumberFormat</code> for the <code>PluralFormat</code> to use.
+ * </p>
+ * Example
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * MessageFormat* msgFmt = new MessageFormat(UnicodeString("{0, plural,
+ * one{{0, number, C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste."),
+ * Locale("fr"), status);
+ * if (U_FAILURE(status)) {
+ * return;
+ * }
+ * Formattable args1[] = {(int32_t)0};
+ * Formattable args2[] = {(int32_t)3};
+ * FieldPosition ignore(FieldPosition::DONT_CARE);
+ * UnicodeString result;
+ * msgFmt->format(args1, 1, result, ignore, status);
+ * cout << result << endl;
+ * result.remove();
+ * msgFmt->format(args2, 1, result, ignore, status);
+ * cout << result << endl;
+ * \endcode
+ * </pre>
+ * Produces the output:<br>
+ * <code>C'est 0,0 fichier dans la liste.</code><br>
+ * <code>Ce sont 3 fichiers dans la liste.</code>
+ * <p>
+ * <strong>Note:</strong><br>
+ * Currently <code>PluralFormat</code>
+ * does not make use of quotes like <code>MessageFormat</code>.
+ * If you use plural format strings with <code>MessageFormat</code> and want
+ * to use a quote sign <code>'</code>, you have to write <code>''</code>.
+ * <code>MessageFormat</code> unquotes this pattern and passes the unquoted
+ * pattern to <code>PluralFormat</code>. It's a bit trickier if you use
+ * nested formats that do quoting. In the example above, we wanted to insert
+ * <code>'</code> in the number format pattern. Since
+ * <code>NumberFormat</code> supports quotes, we had to insert
+ * <code>''</code>. But since <code>MessageFormat</code> unquotes the
+ * pattern before it gets passed to <code>PluralFormat</code>, we have to
+ * double these quotes, i.e. write <code>''''</code>.
+ * </p>
+ * <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:
+ typedef enum fmtToken {
+ none,
+ tLetter,
+ tNumber,
+ tSpace,
+ tNumberSign,
+ tLeftBrace,
+ tRightBrace
+ }fmtToken;
+
+ Locale locale;
+ PluralRules* pluralRules;
+ UnicodeString pattern;
+ Hashtable *fParsedValuesHash;
+ NumberFormat* numberFormat;
+ NumberFormat* replacedNumberFormat;
+
+ PluralFormat(); // default constructor not implemented
+ void init(const PluralRules* rules, const Locale& curlocale, UErrorCode& status);
+ UBool inRange(UChar ch, fmtToken& type);
+ UBool checkSufficientDefinition();
+ void parsingFailure();
+ UnicodeString insertFormattedNumber(double number,
+ UnicodeString& message,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ void copyHashtable(Hashtable *other, UErrorCode& status);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _PLURFMT
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/plurrule.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/plurrule.h
new file mode 100644
index 00000000000..7c05fecca9e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/plurrule.h
@@ -0,0 +1,299 @@
+/*
+*******************************************************************************
+* Copyright (C) 2008-2010, 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"
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+class RuleChain;
+class RuleParser;
+
+/**
+ * Defines rules for mapping positive long 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.
+ *
+ * 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
+ * within_relation = expr ('not')? 'within' range
+ * expr = 'n' ('mod' value)?
+ * value = digit+
+ * digit = 0|1|2|3|4|5|6|7|8|9
+ * range = value'..'value
+ * \endcode
+ * </pre></p>
+ * <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 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:
+ Hashtable *fLocaleStringsHash;
+ UnicodeString mLocaleName;
+ RuleChain *mRules;
+ RuleParser *mParser;
+
+ 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);
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _PLURRULE
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/rbnf.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/rbnf.h
new file mode 100644
index 00000000000..59835d39405
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/rbtz.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/rbtz.h
new file mode 100644
index 00000000000..2be29670cbf
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/regex.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/regex.h
new file mode 100644
index 00000000000..d8d7bc0edf7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/regex.h
@@ -0,0 +1,1772 @@
+/*
+**********************************************************************
+* Copyright (C) 2002-2010, 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;
+
+
+ /**
+ * Flag to disambiguate RegexPattern::matcher signature
+ * @draft ICU 4.6
+ */
+ enum PatternIsUTextFlag { PATTERN_IS_UTEXT };
+
+ /**
+ * 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 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 input The input text to which the regular expression will be applied.
+ * @param flag Must be RegexPattern::PATTERN_IS_UTEXT; used to disambiguate
+ * method signature.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A RegexMatcher object for this pattern and input.
+ *
+ * @draft ICU 4.6
+ */
+ virtual RegexMatcher *matcher(UText *input,
+ PatternIsUTextFlag flag,
+ UErrorCode &status) const;
+
+private:
+ /**
+ * Cause a compilation error if an application accidently attempts to
+ * create a matcher with a (UChar *) string as input rather than
+ * a UnicodeString. Avoids a dangling reference to a temporary string.
+ * <p>
+ * To efficiently work with UChar *strings, wrap the data in a UnicodeString
+ * using one of the aliasing constructors, such as
+ * <code>UnicodeString(UBool isTerminated, const UChar *text, int32_t textLength);</code>
+ * 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 reguluar expression and applies it in a single operation.
+ * Note that if the same pattern needs to be applied repeatedly, this method will be
+ * less efficient than creating and reusing a RegexMatcher object.
+ *
+ * @param regex The regular expression
+ * @param input The string data to be matched
+ * @param pe Receives the position of any syntax errors within the regular expression
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return True if the regular expression exactly matches the full input string.
+ *
+ * @stable ICU 2.4
+ */
+ static UBool U_EXPORT2 matches(const UnicodeString &regex,
+ const UnicodeString &input,
+ UParseError &pe,
+ UErrorCode &status);
+
+
+ /**
+ * Test whether a string matches a regular expression. This convenience function
+ * both compiles the reguluar expression and applies it in a single operation.
+ * Note that if the same pattern needs to be applied repeatedly, this method will be
+ * less efficient than creating and reusing a RegexMatcher object.
+ *
+ * @param regex The regular expression
+ * @param input The string data to be matched
+ * @param pe Receives the position of any syntax errors within the regular expression
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return True if the regular expression exactly matches the full input string.
+ *
+ * @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.
+ * The pattern matches identify delimiters that separate the input
+ * into fields. The input data between the matches becomes the
+ * fields themselves.
+ * <p>
+ * For the best performance on split() operations,
+ * <code>RegexMatcher::split</code> is perferable to this function
+ *
+ * @param input The string to be split into fields. The field delimiters
+ * match the pattern (in the "this" object)
+ * @param dest An array of UnicodeStrings to receive the results of the split.
+ * This is an array of actual UnicodeString objects, not an
+ * array of pointers to strings. Local (stack based) arrays can
+ * work well here.
+ * @param destCapacity The number of elements in the destination array.
+ * If the number of fields found is less than destCapacity, the
+ * extra strings in the destination array are not altered.
+ * If the number of destination strings is less than the number
+ * of fields, the trailing part of the input string, including any
+ * field delimiters, is placed in the last destination string.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The number of fields into which the input string was split.
+ * @stable ICU 2.4
+ */
+ virtual int32_t split(const UnicodeString &input,
+ UnicodeString dest[],
+ int32_t destCapacity,
+ UErrorCode &status) const;
+
+
+ /**
+ * Split a string into fields. Somewhat like split() from Perl.
+ * The pattern matches identify delimiters that separate the input
+ * into fields. The input data between the matches becomes the
+ * fields themselves.
+ * <p>
+ * For the best performance on split() operations,
+ * <code>RegexMatcher::split</code> is perferable to this function
+ *
+ * @param input The string to be split into fields. The field delimiters
+ * match the pattern (in the "this" object)
+ * @param dest An array of 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) 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 reular expression pattern and
+ * input text to which the expression can be applied. It includes methods
+ * for testing for matches, and for find and replace operations.
+ *
+ * <p>Class RegexMatcher is not intended to be subclassed.</p>
+ *
+ * @stable ICU 2.4
+ */
+class U_I18N_API RegexMatcher: public UObject {
+public:
+
+ /**
+ * Construct a RegexMatcher for a regular expression.
+ * This is a convenience method that avoids the need to explicitly create
+ * a RegexPattern object. Note that if several RegexMatchers need to be
+ * created for the same expression, it will be more efficient to
+ * separately create and cache a RegexPattern object, and use
+ * its matcher() method to create the RegexMatcher objects.
+ *
+ * @param regexp The Regular Expression to be compiled.
+ * @param flags Regular expression options, such as case insensitive matching.
+ * @see UREGEX_CASE_INSENSITIVE
+ * @param status Any errors are reported by setting this UErrorCode variable.
+ * @stable ICU 2.6
+ */
+ RegexMatcher(const UnicodeString &regexp, uint32_t flags, UErrorCode &status);
+
+ /**
+ * Construct a RegexMatcher for a regular expression.
+ * This is a convenience method that avoids the need to explicitly create
+ * a RegexPattern object. Note that if several RegexMatchers need to be
+ * created for the same expression, it will be more efficient to
+ * separately create and cache a RegexPattern object, and use
+ * its matcher() method to create the RegexMatcher objects.
+ *
+ * @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 accidently attempts to
+ * create a matcher with a (UChar *) string as input rather than
+ * a UnicodeString. Avoids a dangling reference to a temporary string.
+ * <p>
+ * To efficiently work with UChar *strings, wrap the data in a UnicodeString
+ * using one of the aliasing constructors, such as
+ * <code>UnicodeString(UBool isTerminated, const UChar *text, int32_t textLength);</code>
+ * 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.
+ * Note that copying the entire input string 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 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;
+
+ /**
+ * @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;
+
+ /**
+ * @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;
+
+ /**
+ * @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 UTF8.
+ * @stable ICU 2.4
+ */
+ virtual int32_t end(UErrorCode &status) const;
+
+ /**
+ * @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 specifed 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;
+
+ /**
+ * @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);
+
+private:
+ /**
+ * Cause a compilation error if an application accidently attempts to
+ * reset a matcher with a (UChar *) string as input rather than
+ * a UnicodeString. Avoids a dangling reference to a temporary string.
+ * <p>
+ * To efficiently work with UChar *strings, wrap the data in a UnicodeString
+ * using one of the aliasing constructors, such as
+ * <code>UnicodeString(UBool isTerminated, const UChar *text, int32_t textLength);</code>
+ * 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
+ * @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 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;
+
+ /**
+ * @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;
+
+ /**
+ * @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 boounds.
+ *
+ * @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.
+ * @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 avaliable 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 paramater, 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 paramater, 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.6/i18n/unicode/search.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/search.h
new file mode 100644
index 00000000000..8b829064170
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/search.h
@@ -0,0 +1,569 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2008 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 greater than <tt>position</tt> at which the
+ * string text matches the search pattern. The iterator is adjusted so
+ * that its current index (as returned by <tt>getOffset</tt>) is the
+ * match position if one was found. If a match is not found,
+ * <tt>USEARCH_DONE</tt> will be returned and the iterator will be
+ * adjusted to the index USEARCH_DONE
+ * @param position where search if to start from. If position is less
+ * than or greater than the text range for searching,
+ * an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+ * @param status for errors if it occurs
+ * @return The character index of the first match following
+ * <tt>position</tt>, or <tt>USEARCH_DONE</tt> if there are no
+ * matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t following(int32_t position, UErrorCode &status);
+
+ /**
+ * Returns the last index in the target text at which it matches the
+ * search pattern. The iterator is adjusted so that its current index
+ * (as returned by <tt>getOffset</tt>) is the match position if one was
+ * found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to the index USEARCH_DONE.
+ * @param status for errors if it occurs
+ * @return The index of the first match, or <tt>USEARCH_DONE</tt> if
+ * there are no matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t last(UErrorCode &status);
+
+ /**
+ * Returns the first index less than <tt>position</tt> at which the string
+ * text matches the search pattern. The iterator is adjusted so that its
+ * current index (as returned by <tt>getOffset</tt>) is the match
+ * position if one was found. If a match is not found,
+ * <tt>USEARCH_DONE</tt> will be returned and the iterator will be
+ * adjusted to the index USEARCH_DONE
+ * @param position where search is to start from. If position is less
+ * than or greater than the text range for searching,
+ * an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+ * @param status for errors if it occurs
+ * @return The character index of the first match preceding
+ * <tt>position</tt>, or <tt>USEARCH_DONE</tt> if there are
+ * no matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t preceding(int32_t position, UErrorCode &status);
+
+ /**
+ * Returns the index of the next point at which the text matches the
+ * search pattern, starting from the current position
+ * The iterator is adjusted so that its current index (as returned by
+ * <tt>getOffset</tt>) is the match position if one was found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to a position after the end of the text
+ * string.
+ * @param status for errors if it occurs
+ * @return The index of the next match after the current position,
+ * or <tt>USEARCH_DONE</tt> if there are no more matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t next(UErrorCode &status);
+
+ /**
+ * Returns the index of the previous point at which the string text
+ * matches the search pattern, starting at the current position.
+ * The iterator is adjusted so that its current index (as returned by
+ * <tt>getOffset</tt>) is the match position if one was found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to the index USEARCH_DONE
+ * @param status for errors if it occurs
+ * @return The index of the previous match before the current position,
+ * or <tt>USEARCH_DONE</tt> if there are no more matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t previous(UErrorCode &status);
+
+ /**
+ * Resets the iteration.
+ * Search will begin at the start of the text string if a forward
+ * iteration is initiated before a backwards iteration. Otherwise if a
+ * backwards iteration is initiated before a forwards iteration, the
+ * search will begin at the end of the text string.
+ * @stable ICU 2.0
+ */
+ virtual void reset();
+
+protected:
+ // protected data members ---------------------------------------------
+
+ /**
+ * C search data struct
+ * @stable ICU 2.0
+ */
+ USearch *m_search_;
+
+ /**
+ * Break iterator.
+ * Currently the C++ breakiterator does not have getRules etc to reproduce
+ * another in C. Hence we keep the original around and do the verification
+ * at the end of the match. The user is responsible for deleting this
+ * break iterator.
+ * @stable ICU 2.0
+ */
+ BreakIterator *m_breakiterator_;
+
+ /**
+ * Unicode string version of the search text
+ * @stable ICU 2.0
+ */
+ UnicodeString m_text_;
+
+ // protected constructors and destructors -----------------------------
+
+ /**
+ * Default constructor.
+ * Initializes data to the default values.
+ * @stable ICU 2.0
+ */
+ SearchIterator();
+
+ /**
+ * Constructor for use by subclasses.
+ * @param text The target text to be searched.
+ * @param breakiter A {@link BreakIterator} that is used to restrict the
+ * points at which matches are detected. If
+ * <tt>handleNext</tt> or <tt>handlePrev</tt> finds a
+ * match, but the match's start or end index is not a
+ * boundary as determined by the <tt>BreakIterator</tt>,
+ * the match is rejected and <tt>handleNext</tt> or
+ * <tt>handlePrev</tt> is called again. If this parameter
+ * is <tt>NULL</tt>, no break detection is attempted.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ SearchIterator(const UnicodeString &text,
+ BreakIterator *breakiter = NULL);
+
+ /**
+ * Constructor for use by subclasses.
+ * <p>
+ * Note: No parsing of the text within the <tt>CharacterIterator</tt>
+ * will be done during searching for this version. The block of text
+ * in <tt>CharacterIterator</tt> will be used as it is.
+ * @param text The target text to be searched.
+ * @param breakiter A {@link BreakIterator} that is used to restrict the
+ * points at which matches are detected. If
+ * <tt>handleNext</tt> or <tt>handlePrev</tt> finds a
+ * match, but the match's start or end index is not a
+ * boundary as determined by the <tt>BreakIterator</tt>,
+ * the match is rejected and <tt>handleNext</tt> or
+ * <tt>handlePrev</tt> is called again. If this parameter
+ * is <tt>NULL</tt>, no break detection is attempted.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ SearchIterator(CharacterIterator &text, BreakIterator *breakiter = NULL);
+
+ // protected methods --------------------------------------------------
+
+ /**
+ * Assignment operator. Sets this iterator to have the same behavior,
+ * and iterate over the same text, as the one passed in.
+ * @param that instance to be copied.
+ * @stable ICU 2.0
+ */
+ SearchIterator & operator=(const SearchIterator &that);
+
+ /**
+ * Abstract method which subclasses override to provide the mechanism
+ * for finding the next match in the target text. This allows different
+ * subclasses to provide different search algorithms.
+ * <p>
+ * If a match is found, the implementation should return the index at
+ * which the match starts and should call
+ * <tt>setMatchLength</tt> with the number of characters
+ * in the target text that make up the match. If no match is found, the
+ * method should return USEARCH_DONE.
+ * <p>
+ * @param position The index in the target text at which the search
+ * should start.
+ * @param status for error codes if it occurs.
+ * @return index at which the match starts, else if match is not found
+ * USEARCH_DONE is returned
+ * @see #setMatchLength
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleNext(int32_t position, UErrorCode &status)
+ = 0;
+
+ /**
+ * Abstract method which subclasses override to provide the mechanism for
+ * finding the previous match in the target text. This allows different
+ * subclasses to provide different search algorithms.
+ * <p>
+ * If a match is found, the implementation should return the index at
+ * which the match starts and should call
+ * <tt>setMatchLength</tt> with the number of characters
+ * in the target text that make up the match. If no match is found, the
+ * method should return USEARCH_DONE.
+ * <p>
+ * @param position The index in the target text at which the search
+ * should start.
+ * @param status for error codes if it occurs.
+ * @return index at which the match starts, else if match is not found
+ * USEARCH_DONE is returned
+ * @see #setMatchLength
+ * @stable ICU 2.0
+ */
+ virtual int32_t handlePrev(int32_t position, UErrorCode &status)
+ = 0;
+
+ /**
+ * Sets the length of the currently matched string in the text string to
+ * be searched.
+ * Subclasses' <tt>handleNext</tt> and <tt>handlePrev</tt>
+ * methods should call this when they find a match in the target text.
+ * @param length length of the matched text.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ virtual void setMatchLength(int32_t length);
+
+ /**
+ * Sets the offset of the currently matched string in the text string to
+ * be searched.
+ * Subclasses' <tt>handleNext</tt> and <tt>handlePrev</tt>
+ * methods should call this when they find a match in the target text.
+ * @param position start offset of the matched text.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ virtual void setMatchStart(int32_t position);
+
+ /**
+ * sets match not found
+ * @stable ICU 2.0
+ */
+ void setMatchNotFound();
+};
+
+inline UBool SearchIterator::operator!=(const SearchIterator &that) const
+{
+ return !operator==(that);
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/selfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/selfmt.h
new file mode 100644
index 00000000000..e53f4ce633c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/selfmt.h
@@ -0,0 +1,377 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2010, 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/utypes.h"
+#include "unicode/numfmt.h"
+
+/**
+ * \file
+ * \brief C++ API: SelectFormat object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+
+/**
+ * <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>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>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.
+ * The keywords "male", "female", "mixed" (for groups of people)
+ * and "unknown" are 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>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 text defines the phrase output
+ * for each user-defined keyword.
+ * The pattern is a sequence of <code><i>keyword</i>{<i>phrase</i>}</code>
+ * clauses.
+ * Each clause assigns the phrase <code><i>phrase</i></code>
+ * to the user-defined <code><i>keyword</i></code>.</p>
+ *
+ * <p>Keywords must match the pattern [a-zA-Z][a-zA-Z0-9_-]*; keywords
+ * that don't match this pattern result in the error code
+ * <code>U_ILLEGAL_CHARACTER</code>.
+ * 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>.
+ * If a pattern provides more than one phrase for the same keyword, the
+ * error <code>U_DUPLICATE_KEYWORD</code> is returned.
+ * <br>
+ * Spaces between <code><i>keyword</i></code> and
+ * <code>{<i>phrase</i>}</code> will be ignored; spaces within
+ * <code>{<i>phrase</i>}</code> will be preserved.<p>
+ *
+ * <p>The phrase for a particular select case may contain other message
+ * format patterns. <code>SelectFormat</code> preserves these so that you
+ * can use the strings produced by <code>SelectFormat</code> with other
+ * formatters. If you are using <code>SelectFormat</code> inside a
+ * <code>MessageFormat</code> pattern, <code>MessageFormat</code> will
+ * automatically evaluate the resulting format pattern.
+ * Thus, curly braces (<code>{</code>, <code>}</code>) are <i>only</i> allowed
+ * in phrases to define a nested format pattern.</p>
+ *
+ * <p>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
+ * </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:
+ typedef enum classesForSelectFormat{
+ tStartKeyword,
+ tContinueKeyword,
+ tLeftBrace,
+ tRightBrace,
+ tSpace,
+ tOther
+ }CharacterClass;
+
+ UnicodeString pattern;
+ //Hash to store the keyword, phrase pairs.
+ Hashtable *parsedValuesHash;
+
+ SelectFormat(); // default constructor not implemented.
+ void initHashTable(UErrorCode &status);
+ void cleanHashTable();
+
+ //For the applyPattern , classifies char.s in one of the characterClass.
+ CharacterClass classifyCharacter(UChar ch) const;
+ //Checks if the "other" keyword is present in pattern.
+ UBool checkSufficientDefinition();
+ //Checks if the keyword passed is valid.
+ UBool checkValidKeyword(const UnicodeString& argKeyword) const;
+ void parsingFailure();
+ void copyHashtable(Hashtable *other, UErrorCode& status);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _SELFMT
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/simpletz.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/simpletz.h
new file mode 100644
index 00000000000..871c960586b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/simpletz.h
@@ -0,0 +1,927 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2009, 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 savingsDST The number of milliseconds added to standard time
+ * to get DST time. Default is one hour.
+ * @param status An UErrorCode to receive the status.
+ */
+ void construct(int32_t rawOffsetGMT,
+ int8_t startMonth, int8_t startDay, int8_t startDayOfWeek,
+ int32_t startTime, TimeMode startTimeMode,
+ int8_t endMonth, int8_t endDay, int8_t endDayOfWeek,
+ int32_t endTime, TimeMode endTimeMode,
+ int32_t dstSavings, UErrorCode& status);
+
+ /**
+ * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
+ * on whether the date is after, equal to, or before the rule date. The
+ * millis are compared directly against the ruleMillis, so any
+ * standard-daylight adjustments must be handled by the caller.
+ *
+ * @return 1 if the date is after the rule date, -1 if the date is before
+ * the rule date, or 0 if the date is equal to the rule date.
+ */
+ static int32_t compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen,
+ int8_t dayOfMonth,
+ int8_t dayOfWeek, int32_t millis, int32_t millisDelta,
+ EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOfWeek,
+ int8_t ruleDay, int32_t ruleMillis);
+
+ /**
+ * Given a set of encoded rules in startDay and startDayOfMonth, decode
+ * them and set the startMode appropriately. Do the same for endDay and
+ * endDayOfMonth.
+ * <P>
+ * Upon entry, the day of week variables may be zero or
+ * negative, in order to indicate special modes. The day of month
+ * variables may also be negative.
+ * <P>
+ * Upon exit, the mode variables will be
+ * set, and the day of week and day of month variables will be positive.
+ * <P>
+ * This method also recognizes a startDay or endDay of zero as indicating
+ * no DST.
+ */
+ void decodeRules(UErrorCode& status);
+ void decodeStartRule(UErrorCode& status);
+ void decodeEndRule(UErrorCode& status);
+
+ int8_t startMonth, startDay, startDayOfWeek; // the month, day, DOW, and time DST starts
+ int32_t startTime;
+ TimeMode startTimeMode, endTimeMode; // Mode for startTime, endTime; see TimeMode
+ int8_t endMonth, endDay, endDayOfWeek; // the month, day, DOW, and time DST ends
+ int32_t endTime;
+ int32_t startYear; // the year these DST rules took effect
+ int32_t rawOffset; // the TimeZone's raw GMT offset
+ UBool useDaylight; // flag indicating whether this TimeZone uses DST
+ static const int8_t STATICMONTHLENGTH[12]; // lengths of the months
+ EMode startMode, endMode; // flags indicating what kind of rules the DST rules are
+
+ /**
+ * A positive value indicating the amount of time saved during DST in ms.
+ * Typically one hour; sometimes 30 minutes.
+ */
+ int32_t dstSavings;
+
+ /* Private for BasicTimeZone implementation */
+ void initTransitionRules(UErrorCode& status);
+ void clearTransitionRules(void);
+ void deleteTransitionRules(void);
+ UBool transitionRulesInitialized;
+ InitialTimeZoneRule* initialRule;
+ TimeZoneTransition* firstTransition;
+ AnnualTimeZoneRule* stdRule;
+ AnnualTimeZoneRule* dstRule;
+};
+
+inline void SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth,
+ int32_t dayOfWeek,
+ int32_t time, UErrorCode& status) {
+ setStartRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
+ int32_t time,
+ UErrorCode& status) {
+ setStartRule(month, dayOfMonth, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
+ int32_t dayOfWeek,
+ int32_t time, UBool after, UErrorCode& status) {
+ setStartRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after, status);
+}
+
+inline void SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth,
+ int32_t dayOfWeek,
+ int32_t time, UErrorCode& status) {
+ setEndRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth,
+ int32_t time, UErrorCode& status) {
+ setEndRule(month, dayOfMonth, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, UBool after, UErrorCode& status) {
+ setEndRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after, status);
+}
+
+inline void
+SimpleTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffsetRef,
+ int32_t& dstOffsetRef, UErrorCode& ec) const {
+ TimeZone::getOffset(date, local, rawOffsetRef, dstOffsetRef, ec);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _SIMPLETZ
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/smpdtfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/smpdtfmt.h
new file mode 100644
index 00000000000..14c91d4244b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/smpdtfmt.h
@@ -0,0 +1,1207 @@
+/*
+* Copyright (C) 1997-2010, 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;
+
+/**
+ *
+ * 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 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 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 statuc Filled in with an error code if creating either subobject fails.
+ */
+ void initialize(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Private code-size reduction function used by subParse.
+ * @param text the time text being parsed.
+ * @param start where to start parsing.
+ * @param field the date field being parsed.
+ * @param stringArray the string array to parsed.
+ * @param stringArrayCount the size of the array.
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @return the new start position if matching succeeded; a negative number
+ * indicating matching failure, otherwise.
+ */
+ int32_t matchString(const UnicodeString& text, int32_t start, UCalendarDateFields field,
+ const UnicodeString* stringArray, int32_t stringArrayCount, Calendar& cal) const;
+
+ /**
+ * Private code-size reduction function used by subParse.
+ * @param text the time text being parsed.
+ * @param start where to start parsing.
+ * @param field the date field being parsed.
+ * @param stringArray the string array to parsed.
+ * @param stringArrayCount the size of the array.
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @return the new start position if matching succeeded; a negative number
+ * indicating matching failure, otherwise.
+ */
+ int32_t matchQuarterString(const UnicodeString& text, int32_t start, UCalendarDateFields field,
+ const UnicodeString* stringArray, int32_t stringArrayCount, Calendar& cal) const;
+
+ /**
+ * Private member function that converts the parsed date strings into
+ * timeFields. Returns -start (for ParsePosition) if failed.
+ * @param text the time text to be parsed.
+ * @param start where to start parsing.
+ * @param ch the pattern character for the date field text to be parsed.
+ * @param count the count of a pattern character.
+ * @param obeyCount if true then the count is strictly obeyed.
+ * @param ambiguousYear If true then the two-digit year == the default start year.
+ * @param 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.
+ * @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 isRuleWhiteSpace() characters at
+ * pos in text.
+ */
+ int32_t skipRuleWhiteSpace(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[];
+
+ /**
+ * 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
+
+ /**
+ * 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.6/i18n/unicode/sortkey.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/sortkey.h
new file mode 100644
index 00000000000..ef202dd9ba4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/sortkey.h
@@ -0,0 +1,324 @@
+/*
+ *****************************************************************************
+ * Copyright (C) 1996-2006, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *****************************************************************************
+ *
+ * File sortkey.h
+ *
+ * Created by: Helena Shih
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ *
+ * 6/20/97 helena Java class name change.
+ * 8/18/97 helena Added internal API documentation.
+ * 6/26/98 erm Changed to use byte arrays and memcmp.
+ *****************************************************************************
+ */
+
+#ifndef SORTKEY_H
+#define SORTKEY_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Keys for comparing strings multiple times.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/coll.h"
+
+U_NAMESPACE_BEGIN
+
+/* forward declaration */
+class RuleBasedCollator;
+
+/**
+ *
+ * Collation keys are generated by the Collator class. Use the CollationKey objects
+ * instead of Collator to compare strings multiple times. A CollationKey
+ * preprocesses the comparison information from the Collator object to
+ * make the comparison faster. If you are not going to comparing strings
+ * multiple times, then using the Collator object is generally faster,
+ * since it only processes as much of the string as needed to make a
+ * comparison.
+ * <p> For example (with strength == tertiary)
+ * <p>When comparing "Abernathy" to "Baggins-Smythworthy", Collator
+ * only needs to process a couple of characters, while a comparison
+ * with CollationKeys will process all of the characters. On the other hand,
+ * if you are doing a sort of a number of fields, it is much faster to use
+ * CollationKeys, since you will be comparing strings multiple times.
+ * <p>Typical use of CollationKeys are in databases, where you store a CollationKey
+ * in a hidden field, and use it for sorting or indexing.
+ *
+ * <p>Example of use:
+ * <pre>
+ * \code
+ * UErrorCode success = U_ZERO_ERROR;
+ * Collator* myCollator = Collator::createInstance(success);
+ * CollationKey* keys = new CollationKey [3];
+ * myCollator->getCollationKey("Tom", keys[0], success );
+ * myCollator->getCollationKey("Dick", keys[1], success );
+ * myCollator->getCollationKey("Harry", keys[2], success );
+ *
+ * // Inside body of sort routine, compare keys this way:
+ * CollationKey tmp;
+ * if(keys[0].compareTo( keys[1] ) > 0 ) {
+ * tmp = keys[0]; keys[0] = keys[1]; keys[1] = tmp;
+ * }
+ * //...
+ * \endcode
+ * </pre>
+ * <p>Because Collator::compare()'s algorithm is complex, it is faster to sort
+ * long lists of words by retrieving collation keys with Collator::getCollationKey().
+ * You can then cache the collation keys and compare them using CollationKey::compareTo().
+ * <p>
+ * <strong>Note:</strong> <code>Collator</code>s with different Locale,
+ * CollationStrength and DecompositionMode settings will return different
+ * CollationKeys for the same set of strings. Locales have specific
+ * collation rules, and the way in which secondary and tertiary differences
+ * are taken into account, for example, will result in different CollationKeys
+ * for same strings.
+ * <p>
+
+ * @see Collator
+ * @see RuleBasedCollator
+ * @version 1.3 12/18/96
+ * @author Helena Shih
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+class U_I18N_API CollationKey : public UObject {
+public:
+ /**
+ * This creates an empty collation key based on the null string. An empty
+ * collation key contains no sorting information. When comparing two empty
+ * collation keys, the result is Collator::EQUAL. Comparing empty collation key
+ * with non-empty collation key is always Collator::LESS.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ CollationKey();
+
+
+ /**
+ * Creates a collation key based on the collation key values.
+ * @param values the collation key values
+ * @param count number of collation key values, including trailing nulls.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ CollationKey(const uint8_t* values,
+ int32_t count);
+
+ /**
+ * Copy constructor.
+ * @param other the object to be copied.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ CollationKey(const CollationKey& other);
+
+ /**
+ * Sort key destructor.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ virtual ~CollationKey();
+
+ /**
+ * Assignment operator
+ * @param other the object to be copied.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ const CollationKey& operator=(const CollationKey& other);
+
+ /**
+ * Compare if two collation keys are the same.
+ * @param source the collation key to compare to.
+ * @return Returns true if two collation keys are equal, false otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UBool operator==(const CollationKey& source) const;
+
+ /**
+ * Compare if two collation keys are not the same.
+ * @param source the collation key to compare to.
+ * @return Returns TRUE if two collation keys are different, FALSE otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UBool operator!=(const CollationKey& source) const;
+
+
+ /**
+ * Test to see if the key is in an invalid state. The key will be in an
+ * invalid state if it couldn't allocate memory for some operation.
+ * @return Returns TRUE if the key is in an invalid, FALSE otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UBool isBogus(void) const;
+
+ /**
+ * Returns a pointer to the collation key values. The storage is owned
+ * by the collation key and the pointer will become invalid if the key
+ * is deleted.
+ * @param count the output parameter of number of collation key values,
+ * including any trailing nulls.
+ * @return a pointer to the collation key values.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ const uint8_t* getByteArray(int32_t& count) const;
+
+#ifdef U_USE_COLLATION_KEY_DEPRECATES
+ /**
+ * Extracts the collation key values into a new array. The caller owns
+ * this storage and should free it.
+ * @param count the output parameter of number of collation key values,
+ * including any trailing nulls.
+ * @obsolete ICU 2.6. Use getByteArray instead since this API will be removed in that release.
+ */
+ uint8_t* toByteArray(int32_t& count) const;
+#endif
+
+ /**
+ * Convenience method which does a string(bit-wise) comparison of the
+ * two collation keys.
+ * @param target target collation key to be compared with
+ * @return Returns Collator::LESS if sourceKey &lt; targetKey,
+ * Collator::GREATER if sourceKey > targetKey and Collator::EQUAL
+ * otherwise.
+ * @deprecated ICU 2.6 use the overload with error code
+ */
+ Collator::EComparisonResult compareTo(const CollationKey& target) const;
+
+ /**
+ * Convenience method which does a string(bit-wise) comparison of the
+ * two collation keys.
+ * @param target target collation key to be compared with
+ * @param status error code
+ * @return Returns UCOL_LESS if sourceKey &lt; targetKey,
+ * UCOL_GREATER if sourceKey > targetKey and UCOL_EQUAL
+ * otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UCollationResult compareTo(const CollationKey& target, UErrorCode &status) const;
+
+ /**
+ * Creates an integer that is unique to the collation key. NOTE: this
+ * is not the same as String.hashCode.
+ * <p>Example of use:
+ * <pre>
+ * . UErrorCode status = U_ZERO_ERROR;
+ * . Collator *myCollation = Collator::createInstance(Locale::US, status);
+ * . if (U_FAILURE(status)) return;
+ * . CollationKey key1, key2;
+ * . UErrorCode status1 = U_ZERO_ERROR, status2 = U_ZERO_ERROR;
+ * . myCollation->getCollationKey("abc", key1, status1);
+ * . if (U_FAILURE(status1)) { delete myCollation; return; }
+ * . myCollation->getCollationKey("ABC", key2, status2);
+ * . if (U_FAILURE(status2)) { delete myCollation; return; }
+ * . // key1.hashCode() != key2.hashCode()
+ * </pre>
+ * @return the hash value based on the string's collation order.
+ * @see UnicodeString#hashCode
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ int32_t hashCode(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ /**
+ * Returns an array of the collation key values as 16-bit integers.
+ * The caller owns the storage and must delete it.
+ * @param values Output param of the collation key values.
+ * @param count output parameter of the number of collation key values
+ * @return a pointer to an array of 16-bit collation key values.
+ */
+ void adopt(uint8_t *values, int32_t count);
+
+ /*
+ * Creates a collation key with a string.
+ */
+
+ /**
+ * If this CollationKey has capacity less than newSize,
+ * its internal capacity will be increased to newSize.
+ * @param newSize minimum size this CollationKey has to have
+ * @return this CollationKey
+ */
+ CollationKey& ensureCapacity(int32_t newSize);
+ /**
+ * Set the CollationKey to a "bogus" or invalid state
+ * @return this CollationKey
+ */
+ CollationKey& setToBogus(void);
+ /**
+ * Resets this CollationKey to an empty state
+ * @return this CollationKey
+ */
+ CollationKey& reset(void);
+
+ /**
+ * Allow private access to RuleBasedCollator
+ */
+ friend class RuleBasedCollator;
+ /**
+ * Bogus status
+ */
+ UBool fBogus;
+ /**
+ * Size of fBytes used to store the sortkey. i.e. up till the
+ * null-termination.
+ */
+ int32_t fCount;
+ /**
+ * Full size of the fBytes
+ */
+ int32_t fCapacity;
+ /**
+ * Unique hash value of this CollationKey
+ */
+ int32_t fHashCode;
+ /**
+ * Array to store the sortkey
+ */
+ uint8_t* fBytes;
+
+};
+
+inline UBool
+CollationKey::operator!=(const CollationKey& other) const
+{
+ return !(*this == other);
+}
+
+inline UBool
+CollationKey::isBogus() const
+{
+ return fBogus;
+}
+
+inline const uint8_t*
+CollationKey::getByteArray(int32_t &count) const
+{
+ count = fCount;
+ return fBytes;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/stsearch.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/stsearch.h
new file mode 100644
index 00000000000..8499752e6d0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/tblcoll.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/tblcoll.h
new file mode 100644
index 00000000000..8e2225192f2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/tblcoll.h
@@ -0,0 +1,966 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2010, 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);
+
+ /**
+ * Get the current reordering of scripts (if one has been set).
+ * @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 length of the array of the script ordering.
+ * @see ucol_getReorderCodes
+ * @internal
+ */
+ virtual int32_t getReorderCodes(int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode& status) const;
+
+ /**
+ * Set the ordering of scripts for this collator.
+ * @param reorderCodes An array of script codes in the new order.
+ * @param reorderCodesLength The length of reorderCodes.
+ * @see ucol_setReorderCodes
+ * @internal
+ */
+ virtual void setReorderCodes(const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ 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
+ * @param rules corresponding collation rules
+ */
+ void setUCollator(UCollator *collator);
+
+public:
+ /**
+ * Get UCollator data struct. Used only by StringSearch & intltest.
+ * @return UCollator data struct
+ * @internal
+ */
+ const UCollator * getUCollator();
+
+protected:
+ /**
+ * Used internally by registraton to define the requested and valid locales.
+ * @param requestedLocale the requsted locale
+ * @param validLocale the valid locale
+ * @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.6/i18n/unicode/timezone.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/timezone.h
new file mode 100644
index 00000000000..a06d33d905a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/timezone.h
@@ -0,0 +1,777 @@
+/*************************************************************************
+* Copyright (c) 1997-2010, International Business Machines Corporation
+* and others. All Rights Reserved.
+**************************************************************************
+*
+* File TIMEZONE.H
+*
+* Modification History:
+*
+* Date Name Description
+* 04/21/97 aliu Overhauled header.
+* 07/09/97 helena Changed createInstance to createDefault.
+* 08/06/97 aliu Removed dependency on internal header for Hashtable.
+* 08/10/98 stephen Changed getDisplayName() API conventions to match
+* 08/19/98 stephen Changed createTimeZone() to never return 0
+* 09/02/98 stephen Sync to JDK 1.2 8/31
+* - Added getOffset(... monthlen ...)
+* - Added hasSameRules()
+* 09/15/98 stephen Added getStaticClassID
+* 12/03/99 aliu Moved data out of static table into icudata.dll.
+* Hashtable replaced by new static data structures.
+* 12/14/99 aliu Made GMT public.
+* 08/15/01 grhoten Made GMT private and added the getGMT() function
+**************************************************************************
+*/
+
+#ifndef TIMEZONE_H
+#define TIMEZONE_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: TimeZone object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/ures.h"
+
+U_NAMESPACE_BEGIN
+
+class StringEnumeration;
+
+/**
+ *
+ * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
+ * savings.
+ *
+ * <p>
+ * Typically, you get a <code>TimeZone</code> using <code>createDefault</code>
+ * which creates a <code>TimeZone</code> based on the time zone where the program
+ * is running. For example, for a program running in Japan, <code>createDefault</code>
+ * creates a <code>TimeZone</code> object based on Japanese Standard Time.
+ *
+ * <p>
+ * You can also get a <code>TimeZone</code> using <code>createTimeZone</code> along
+ * with a time zone ID. For instance, the time zone ID for the 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 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.
+ * @stable ICU 2.0
+ */
+ virtual UBool useDaylightTime(void) const = 0;
+
+ /**
+ * Queries if the given date is in daylight savings time in
+ * this time zone.
+ * This method is wasteful since it creates a new GregorianCalendar and
+ * deletes it each time it is called. This is a deprecated method
+ * and provided only for Java compatibility.
+ *
+ * @param date the given UDate.
+ * @param status Output param filled in with success/error code.
+ * @return true if the given date is in daylight savings time,
+ * false, otherwise.
+ * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& status) const = 0;
+
+ /**
+ * Returns true if this zone has the same rule and offset as another zone.
+ * That is, if this zone differs only in ID, if at all.
+ * @param other the <code>TimeZone</code> object to be compared with
+ * @return true if the given zone is the same as this one,
+ * with the possible exception of the ID
+ * @stable ICU 2.0
+ */
+ virtual UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * Clones TimeZone objects polymorphically. Clients are responsible for deleting
+ * the TimeZone object cloned.
+ *
+ * @return A new copy of this TimeZone object.
+ * @stable ICU 2.0
+ */
+ virtual TimeZone* clone(void) const = 0;
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID().
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. This method is to
+ * implement a simple version of RTTI, since not all C++ compilers support genuine
+ * RTTI. Polymorphic operator==() and clone() methods call this method.
+ * <P>
+ * Concrete subclasses of TimeZone must use the UOBJECT_DEFINE_RTTI_IMPLEMENTATION
+ * macro from uobject.h in their implementation to provide correct RTTI information.
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const = 0;
+
+ /**
+ * Returns the amount of time to be added to local standard time
+ * to get local wall clock time.
+ * <p>
+ * The default implementation always returns 3600000 milliseconds
+ * (i.e., one hour) if this time zone observes Daylight Saving
+ * Time. Otherwise, 0 (zero) is returned.
+ * <p>
+ * If an underlying TimeZone implementation subclass supports
+ * historical Daylight Saving Time changes, this method returns
+ * the known latest daylight saving value.
+ *
+ * @return the amount of saving time in milliseconds
+ * @stable ICU 3.6
+ */
+ virtual int32_t getDSTSavings() const;
+
+protected:
+
+ /**
+ * Default constructor. ID is initialized to the empty string.
+ * @stable ICU 2.0
+ */
+ TimeZone();
+
+ /**
+ * Construct a TimeZone with a given ID.
+ * @param id a system time zone ID
+ * @stable ICU 2.0
+ */
+ TimeZone(const UnicodeString &id);
+
+ /**
+ * Copy constructor.
+ * @param source the object to be copied.
+ * @stable ICU 2.0
+ */
+ TimeZone(const TimeZone& source);
+
+ /**
+ * Default assignment operator.
+ * @param right the object to be copied.
+ * @stable ICU 2.0
+ */
+ TimeZone& operator=(const TimeZone& right);
+
+ /**
+ * Utility function. For internally loading rule data.
+ * @param top Top resource bundle for tz data
+ * @param ruleid ID of rule to load
+ * @param oldbundle Old bundle to reuse or NULL
+ * @param status Status parameter
+ * @return either a new bundle or *oldbundle
+ * @internal
+ */
+ static UResourceBundle* loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode&status);
+
+private:
+ friend class ZoneMeta;
+
+
+ static TimeZone* createCustomTimeZone(const UnicodeString&); // Creates a time zone based on the string.
+
+ /**
+ * 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.
+ * @param id zone id string
+ * @return the region associated with the given zone
+ */
+ static const UChar* getRegion(const UnicodeString& id);
+
+ /**
+ * 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& min, int32_t& sec);
+
+ /**
+ * 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 netative 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);
+
+ UnicodeString fID; // this time zone's ID
+
+};
+
+
+// -------------------------------------
+
+inline UnicodeString&
+TimeZone::getID(UnicodeString& ID) const
+{
+ ID = fID;
+ return ID;
+}
+
+// -------------------------------------
+
+inline void
+TimeZone::setID(const UnicodeString& ID)
+{
+ fID = ID;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif //_TIMEZONE
+//eof
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/tmunit.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/tmunit.h
new file mode 100644
index 00000000000..6eda105c12f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/tmutamt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/tmutamt.h
new file mode 100644
index 00000000000..bd2b8a4a9e2
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/tmutfmt.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/tmutfmt.h
new file mode 100644
index 00000000000..540be3f7eb6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/tmutfmt.h
@@ -0,0 +1,272 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2010, 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"
+
+/**
+ * @internal ICU 4.2
+ */
+
+union UHashTok;
+
+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:
+
+ /**
+ * 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.2
+ */
+ enum EStyle {
+ kFull = 0,
+ kAbbreviate = 1,
+ kTotal = kAbbreviate + 1
+ };
+
+ /**
+ * 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.2
+ */
+ TimeUnitFormat(const Locale& locale, EStyle 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;
+ EStyle fStyle;
+
+ void create(const Locale& locale, EStyle 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(EStyle 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(EStyle style, const char* key, UErrorCode& status);
+
+ // fill in fTimeUnitToCountToPatterns from locale fall-back chain
+ void searchInLocaleChain(EStyle style, const char* key, const char* localeName,
+ TimeUnit::UTimeUnitFields field, const char*,
+ 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.6/i18n/unicode/translit.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/translit.h
new file mode 100644
index 00000000000..b77eef54f25
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/translit.h
@@ -0,0 +1,1320 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2008, 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.6/i18n/unicode/tzrule.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/tzrule.h
new file mode 100644
index 00000000000..afa40148d42
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/tztrans.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/tztrans.h
new file mode 100644
index 00000000000..94b8e91267a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/ucal.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucal.h
new file mode 100644
index 00000000000..997af153d43
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucal.h
@@ -0,0 +1,1285 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, 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
+ */
+
+/** 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;
+
+/**
+ * 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);
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/unicode/ucol.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucol.h
new file mode 100644
index 00000000000..4a4cd606e8a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucol.h
@@ -0,0 +1,1227 @@
+/*
+*******************************************************************************
+* Copyright (c) 1996-2010, 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"
+
+/**
+ * \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.
+ * @internal
+ */
+typedef enum {
+ UCOL_REORDER_CODE_SPACE = 0x1000,
+ UCOL_REORDER_CODE_FIRST = UCOL_REORDER_CODE_SPACE,
+ UCOL_REORDER_CODE_PUNCTUATION = 0x1001,
+ UCOL_REORDER_CODE_SYMBOL = 0x1002,
+ UCOL_REORDER_CODE_CURRENCY = 0x1003,
+ UCOL_REORDER_CODE_DIGIT = 0x1004,
+ 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);
+
+/**
+ * Get the current reordering of scripts (if one has been set).
+ * @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 length of the array of the script ordering.
+ * @see ucol_setReorderCodes
+ * @internal
+ */
+U_INTERNAL int32_t U_EXPORT2
+ucol_getReorderCodes(const UCollator* coll,
+ int32_t* dest,
+ int32_t destCapacity,
+ UErrorCode *pErrorCode);
+
+/**
+ * Set the ordering of scripts for this collator.
+ * @param coll The UCollator to set.
+ * @param reorderCodes An array of script codes in the new order.
+ * @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
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+ucol_setReorderCodes(UCollator* coll,
+ const int32_t* reorderCodes,
+ int32_t reorderCodesLength,
+ 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.6/i18n/unicode/ucoleitr.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucoleitr.h
new file mode 100644
index 00000000000..419cb9f7de6
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/ucsdet.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucsdet.h
new file mode 100644
index 00000000000..dc492ee229e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/ucurr.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucurr.h
new file mode 100644
index 00000000000..cee8e21027b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/ucurr.h
@@ -0,0 +1,316 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2010, 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);
+
+/**
+ * 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.6/i18n/unicode/udat.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/udat.h
new file mode 100644
index 00000000000..d480c7da514
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/udatpg.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/udatpg.h
new file mode 100644
index 00000000000..3dc7e89f2df
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/uldnames.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/uldnames.h
new file mode 100644
index 00000000000..4a119ea2653
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/ulocdata.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/ulocdata.h
new file mode 100644
index 00000000000..3431f25e248
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/ulocdata.h
@@ -0,0 +1,263 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2010, 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 {
+ ULOCDATA_ES_STANDARD=0, /* Basic set */
+ ULOCDATA_ES_AUXILIARY=1, /* Auxiliary set */
+ ULOCDATA_ES_COUNT=2
+} ULocaleDataExemplarSetType;
+
+/** The possible types of delimiters.
+ * @stable ICU 3.4
+ */
+typedef enum ULocaleDataDelimiterType {
+ ULOCDATA_QUOTATION_START = 0, /* Quotation start */
+ ULOCDATA_QUOTATION_END = 1, /* Quotation end */
+ ULOCDATA_ALT_QUOTATION_START = 2, /* Alternate quotation start */
+ ULOCDATA_ALT_QUOTATION_END = 3, /* Alternate quotation end */
+ 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.
+ * @return USet* Either fillIn, or if fillIn is NULL, a pointer to
+ * a newly-allocated USet that the user must close.
+ * @stable ICU 3.4
+ */
+U_STABLE USet* U_EXPORT2
+ulocdata_getExemplarSet(ULocaleData *uld, USet *fillIn,
+ uint32_t options, ULocaleDataExemplarSetType extype, UErrorCode *status);
+
+/**
+ * Returns one of the delimiter strings associated with a locale.
+ *
+ * @param uld Pointer to the locale data object from which the
+ * delimiter string is to be retrieved.
+ * @param type the type of delimiter to be retrieved.
+ * @param result A pointer to a buffer to receive the result.
+ * @param resultLength The maximum size of result.
+ * @param status Pointer to an error code value
+ * @return int32_t The total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type, UChar *result, int32_t resultLength, UErrorCode *status);
+
+/**
+ * Enumeration for representing the measurement systems.
+ * @stable ICU 2.8
+ */
+typedef enum UMeasurementSystem {
+ UMS_SI, /** Measurement system specified by SI otherwise known as Metric system. */
+ UMS_US, /** Measurement system followed in the United States of America. */
+ UMS_LIMIT
+} UMeasurementSystem;
+
+/**
+ * Returns the measurement system used in the locale specified by the localeID.
+ * Please note that this API will change in ICU 3.6 and will use an ulocdata object.
+ *
+ * @param localeID The id of the locale for which the measurement system to be retrieved.
+ * @param status Must be a valid pointer to an error code value,
+ * which must not indicate a failure before the function call.
+ * @return UMeasurementSystem the measurement system used in the locale.
+ * @stable ICU 2.8
+ */
+U_STABLE UMeasurementSystem U_EXPORT2
+ulocdata_getMeasurementSystem(const char *localeID, UErrorCode *status);
+
+/**
+ * Returns the element gives the normal business letter size, and customary units.
+ * The units for the numbers are always in <em>milli-meters</em>.
+ * For US since 8.5 and 11 do not yeild an integral value when converted to milli-meters,
+ * the values are rounded off.
+ * So for A4 size paper the height and width are 297 mm and 210 mm repectively,
+ * and for US letter size the height and width are 279 mm and 216 mm respectively.
+ * Please note that this API will change in ICU 3.6 and will use an ulocdata object.
+ *
+ * @param localeID The id of the locale for which the paper size information to be retrieved.
+ * @param height A pointer to int to recieve the height information.
+ * @param width A pointer to int to recieve the width information.
+ * @param status Must be a valid pointer to an error code value,
+ * which must not indicate a failure before the function call.
+ * @stable ICU 2.8
+ */
+U_STABLE void U_EXPORT2
+ulocdata_getPaperSize(const char *localeID, int32_t *height, int32_t *width, UErrorCode *status);
+
+/**
+ * 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.6/i18n/unicode/umsg.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/umsg.h
new file mode 100644
index 00000000000..7d08fd3b79b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/umsg.h
@@ -0,0 +1,709 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2010, 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>Message Format C API </h2>
+ *
+ * Provides means to produce concatenated messages in language-neutral way.
+ * Use this for all concatenations that show up to end users.
+ * <P>
+ * Takes a set of objects, formats them, then inserts the formatted
+ * strings into the pattern at the appropriate places.
+ * <P>
+ * Here are some examples of usage:
+ * Example 1:
+ * <pre>
+ * \code
+ * UChar *result, *tzID, *str;
+ * UChar pattern[100];
+ * int32_t resultLengthOut, resultlength;
+ * UCalendar *cal;
+ * UDate d1;
+ * UDateFormat *def1;
+ * UErrorCode status = U_ZERO_ERROR;
+ *
+ * str=(UChar*)malloc(sizeof(UChar) * (strlen("disturbance in force") +1));
+ * u_uastrcpy(str, "disturbance in force");
+ * tzID=(UChar*)malloc(sizeof(UChar) * 4);
+ * u_uastrcpy(tzID, "PST");
+ * cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_TRADITIONAL, &status);
+ * ucal_setDateTime(cal, 1999, UCAL_MARCH, 18, 0, 0, 0, &status);
+ * d1=ucal_getMillis(cal, &status);
+ * u_uastrcpy(pattern, "On {0, date, long}, there was a {1} on planet {2,number,integer}");
+ * resultlength=0;
+ * resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), NULL, resultlength, &status, d1, str, 7);
+ * if(status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * resultlength=resultLengthOut+1;
+ * result=(UChar*)realloc(result, sizeof(UChar) * resultlength);
+ * u_formatMessage( "en_US", pattern, u_strlen(pattern), result, resultlength, &status, d1, str, 7);
+ * }
+ * printf("%s\n", austrdup(result) );//austrdup( a function used to convert UChar* to char*)
+ * //output>: "On March 18, 1999, there was a disturbance in force on planet 7
+ * \endcode
+ * </pre>
+ * Typically, the message format will come from resources, and the
+ * arguments will be dynamically set at runtime.
+ * <P>
+ * Example 2:
+ * <pre>
+ * \code
+ * UChar* str;
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar *result;
+ * UChar pattern[100];
+ * int32_t resultlength, resultLengthOut, i;
+ * double testArgs= { 100.0, 1.0, 0.0};
+ *
+ * str=(UChar*)malloc(sizeof(UChar) * 10);
+ * u_uastrcpy(str, "MyDisk");
+ * u_uastrcpy(pattern, "The disk {1} contains {0,choice,0#no files|1#one file|1<{0,number,integer} files}");
+ * for(i=0; i<3; i++){
+ * resultlength=0;
+ * resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), NULL, resultlength, &status, testArgs[i], str);
+ * if(status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * resultlength=resultLengthOut+1;
+ * result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ * u_formatMessage( "en_US", pattern, u_strlen(pattern), result, resultlength, &status, testArgs[i], str);
+ * }
+ * printf("%s\n", austrdup(result) ); //austrdup( a function used to convert UChar* to char*)
+ * free(result);
+ * }
+ * // output, with different testArgs:
+ * // output: The disk "MyDisk" contains 100 files.
+ * // output: The disk "MyDisk" contains one file.
+ * // output: The disk "MyDisk" contains no files.
+ * \endcode
+ * </pre>
+ *
+ *
+ * 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>
+ *
+
+ * The pattern is of the following form. Legend:
+ * <pre>
+ * \code
+ * {optional item}
+ * (group that may be repeated)*
+ * \endcode
+ * </pre>
+ * Do not confuse optional items with items inside quotes braces, such
+ * as this: "{". Quoted braces are literals.
+ * <pre>
+ * \code
+ * messageFormatPattern := string ( "{" messageFormatElement "}" string )*
+ *
+ * messageFormatElement := argument { "," elementFormat }
+ *
+ * elementFormat := "time" { "," datetimeStyle }
+ * | "date" { "," datetimeStyle }
+ * | "number" { "," numberStyle }
+ * | "choice" "," choiceStyle
+ * | "select" "," selectStyle
+ *
+ * datetimeStyle := "short"
+ * | "medium"
+ * | "long"
+ * | "full"
+ * | dateFormatPattern
+ *
+ * numberStyle := "currency"
+ * | "percent"
+ * | "integer"
+ * | numberFormatPattern
+ *
+ * choiceStyle := choiceFormatPattern
+ *
+ * selectStyle := selectFormatPattern
+ * \endcode
+ * </pre>
+ * If there is no elementFormat, then the argument must be a string,
+ * which is substituted. If there is no dateTimeStyle or numberStyle,
+ * then the default format is used (e.g. NumberFormat.getInstance(),
+ * DateFormat.getDefaultTime() or DateFormat.getDefaultDate(). For
+ * a ChoiceFormat, the pattern must always be specified, since there
+ * is no default.
+ * <P>
+ * In strings, single quotes can be used to quote the "{" sign if
+ * necessary. A real single quote is represented by ''. Inside a
+ * messageFormatElement, quotes are [not] removed. For example,
+ * {1,number,$'#',##} will produce a number format with the pound-sign
+ * quoted, with a result such as: "$#31,45".
+ * <P>
+ * If a pattern is used, then unquoted braces in the pattern, if any,
+ * must match: that is, "ab {0} de" and "ab '}' de" are ok, but "ab
+ * {0'}' de" and "ab } de" are not.
+ * <p>
+ * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
+ * format patterns unfortunately have shown to be somewhat confusing.
+ * In particular, it isn't always obvious to localizers whether single
+ * quotes need to be doubled or not. Make sure to inform localizers about
+ * the rules, and tell them (for example, by using comments in resource
+ * bundle source files) which strings will be processed by MessageFormat.
+ * Note that localizers may need to use single quotes in translated
+ * strings where the original version doesn't have them.
+ * <br>Note also that the simplest way to avoid the problem is to
+ * use the real apostrophe (single quote) character U+2019 (') for
+ * human-readable text, and to use the ASCII apostrophe (U+0027 ' )
+ * only in program syntax, like quoting in MessageFormat.
+ * See the annotations for U+0027 Apostrophe in The Unicode Standard.</p>
+ * </dl>
+ * <P>
+ * The argument is a number from 0 to 9, which corresponds to the
+ * arguments presented in an array to be formatted.
+ * <P>
+ * It is ok to have unused arguments in the array. With missing
+ * arguments or arguments that are not of the right class for the
+ * specified format, a failing UErrorCode result is set.
+ * <P>
+
+ * <P>
+ * [Note:] As we see above, the string produced by a choice Format in
+ * MessageFormat is treated specially; occurances of '{' are used to
+ * indicated subformats.
+ * <P>
+ * [Note:] Formats are numbered by order of variable in the string.
+ * This is [not] the same as the argument numbering!
+ * <pre>
+ * \code
+ * For example: with "abc{2}def{3}ghi{0}...",
+ *
+ * format0 affects the first variable {2}
+ * format1 affects the second variable {3}
+ * format2 affects the second variable {0}
+ * \endcode
+ * </pre>
+ * and so on.
+ */
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments specified
+ * in pattern.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @see u_parseMessage
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_formatMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param ap A variable-length argument list containing the arguments specified
+ * @param status A pointer to an UErrorCode to receive any errors
+ * in pattern.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @see u_parseMessage
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vformatMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_parseMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param ap A variable-length argument list containing the arguments
+ * @param status A pointer to an UErrorCode to receive any errors
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_vparseMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments specified
+ * in pattern.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @see u_parseMessage
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_formatMessageWithError( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError *parseError,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @param ap A variable-length argument list containing the arguments specified
+ * @param status A pointer to an UErrorCode to receive any errors
+ * in pattern.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vformatMessageWithError( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError* parseError,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_parseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UParseError *parseError,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param ap A variable-length argument list containing the arguments
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_vparseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UParseError *parseError,
+ UErrorCode* status);
+
+/*----------------------- New experimental API --------------------------- */
+/**
+ * The message format object
+ * @stable ICU 2.0
+ */
+typedef void* UMessageFormat;
+
+
+/**
+ * Open a message formatter with given pattern and for the given locale.
+ * @param pattern A pattern specifying the format to use.
+ * @param patternLength Length of the pattern to use
+ * @param locale The locale for which the messages are formatted.
+ * @param parseError A pointer to UParseError struct to receive any errors
+ * occured during parsing. Can be NULL.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UMessageFormat to use for formatting
+ * messages, or 0 if an error occurred.
+ * @stable ICU 2.0
+ */
+U_STABLE UMessageFormat* U_EXPORT2
+umsg_open( const UChar *pattern,
+ int32_t patternLength,
+ const char *locale,
+ UParseError *parseError,
+ UErrorCode *status);
+
+/**
+ * Close a UMessageFormat.
+ * Once closed, a UMessageFormat may no longer be used.
+ * @param format The formatter to close.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+umsg_close(UMessageFormat* format);
+
+#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.6/i18n/unicode/unirepl.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/unirepl.h
new file mode 100644
index 00000000000..6b7746b2213
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/unum.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/unum.h
new file mode 100644
index 00000000000..1102bab58b3
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/unum.h
@@ -0,0 +1,999 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, 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 pattern
+ * @stable ICU 3.0
+ */
+ UNUM_PATTERN_DECIMAL=0,
+ /** Decimal format */
+ UNUM_DECIMAL=1,
+ /** Currency format */
+ UNUM_CURRENCY,
+ /** Percent format */
+ UNUM_PERCENT,
+ /** Scientific format */
+ UNUM_SCIENTIFIC,
+ /** Spellout rule-based format */
+ UNUM_SPELLOUT,
+ /**
+ * Ordinal rule-based format
+ * @stable ICU 3.0
+ */
+ UNUM_ORDINAL,
+ /**
+ * Duration rule-based format
+ * @stable ICU 3.0
+ */
+ UNUM_DURATION,
+ /**
+ * Numbering system rule-based format
+ * @stable ICU 4.2
+ */
+ UNUM_NUMBERING_SYSTEM,
+ /**
+ * Rule-based format defined by pattern
+ * @stable ICU 3.0
+ */
+ UNUM_PATTERN_RULEBASED,
+ /** Default format */
+ UNUM_DEFAULT = UNUM_DECIMAL,
+ /** (Alias for UNUM_PATTERN_DECIMAL) */
+ UNUM_IGNORE = UNUM_PATTERN_DECIMAL
+} UNumberFormatStyle;
+
+/** The possible number format rounding modes.
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatRoundingMode {
+ UNUM_ROUND_CEILING,
+ UNUM_ROUND_FLOOR,
+ UNUM_ROUND_DOWN,
+ UNUM_ROUND_UP,
+ /**
+ * Half-even rounding, misspelled name
+ * @deprecated, ICU 3.8
+ */
+ UNUM_FOUND_HALFEVEN,
+ UNUM_ROUND_HALFDOWN,
+ UNUM_ROUND_HALFUP,
+ /**
+ * Half-even rounding
+ * @stable, ICU 3.8
+ */
+ UNUM_ROUND_HALFEVEN = UNUM_FOUND_HALFEVEN
+} UNumberFormatRoundingMode;
+
+/** The possible number format pad positions.
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatPadPosition {
+ UNUM_PAD_BEFORE_PREFIX,
+ UNUM_PAD_AFTER_PREFIX,
+ UNUM_PAD_BEFORE_SUFFIX,
+ UNUM_PAD_AFTER_SUFFIX
+} UNumberFormatPadPosition;
+
+/**
+ * Create and return a new UNumberFormat for formatting and parsing
+ * numbers. A UNumberFormat may be used to format numbers by calling
+ * {@link #unum_format }, and to parse numbers by calling {@link #unum_parse }.
+ * The caller must call {@link #unum_close } when done to release resources
+ * used by this object.
+ * @param style The type of number format to open: one of
+ * UNUM_DECIMAL, UNUM_CURRENCY, UNUM_PERCENT, UNUM_SCIENTIFIC, UNUM_SPELLOUT,
+ * UNUM_PATTERN_DECIMAL, UNUM_PATTERN_RULEBASED, or UNUM_DEFAULT.
+ * If UNUM_PATTERN_DECIMAL or UNUM_PATTERN_RULEBASED is passed then the
+ * number format is opened using the given pattern, which must conform
+ * to the syntax described in DecimalFormat or RuleBasedNumberFormat,
+ * respectively.
+ * @param pattern A pattern specifying the format to use.
+ * This parameter is ignored unless the style is
+ * UNUM_PATTERN_DECIMAL or UNUM_PATTERN_RULEBASED.
+ * @param patternLength The number of characters in the pattern, or -1
+ * if null-terminated. This parameter is ignored unless the style is
+ * UNUM_PATTERN.
+ * @param locale A locale identifier to use to determine formatting
+ * and parsing conventions, or NULL to use the default locale.
+ * @param parseErr A pointer to a UParseError struct to receive the
+ * details of any parsing errors, or NULL if no parsing error details
+ * are desired.
+ * @param status A pointer to an input-output UErrorCode.
+ * @return A pointer to a newly created UNumberFormat, or NULL if an
+ * error occurred.
+ * @see unum_close
+ * @see DecimalFormat
+ * @stable ICU 2.0
+ */
+U_STABLE UNumberFormat* U_EXPORT2
+unum_open( UNumberFormatStyle style,
+ const UChar* pattern,
+ int32_t patternLength,
+ const char* locale,
+ UParseError* parseErr,
+ UErrorCode* status);
+
+
+/**
+* Close a UNumberFormat.
+* Once closed, a UNumberFormat may no longer be used.
+* @param fmt The formatter to close.
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+unum_close(UNumberFormat* fmt);
+
+#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.6/i18n/unicode/uregex.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/uregex.h
new file mode 100644
index 00000000000..0663e7e7b5b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/uregex.h
@@ -0,0 +1,1451 @@
+/*
+**********************************************************************
+* Copyright (C) 2004-2010, 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 rexpression, plus the results
+ * of a match operation.
+ * @stable ICU 3.0
+ */
+typedef struct URegularExpression URegularExpression;
+
+
+/**
+ * Constants for Regular Expression Match Modes.
+ * @stable ICU 2.4
+ */
+typedef enum URegexpFlag{
+
+#ifndef U_HIDE_DRAFT_API
+ /** Forces normalization of pattern and strings.
+ Not implemented yet, just a placeholder, hence draft.
+ @draft ICU 2.4 */
+ UREGEX_CANON_EQ = 128,
+#endif
+ /** Enable case insensitive matching. @stable ICU 2.4 */
+ UREGEX_CASE_INSENSITIVE = 2,
+
+ /** Allow white space and comments within patterns @stable ICU 2.4 */
+ UREGEX_COMMENTS = 4,
+
+ /** If set, '.' matches line terminators, otherwise '.' matching stops at line end.
+ * @stable ICU 2.4 */
+ UREGEX_DOTALL = 32,
+
+ /** 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 specail
+ * 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 termintated.
+ * @param flags Flags that alter the default matching behavior for
+ * the regular expression, UREGEX_CASE_INSENSITIVE, for
+ * example. For default behavior, set this parameter to zero.
+ * See <code>enum URegexpFlag</code>. All desired flags
+ * are bitwise-ORed together.
+ * @param pe Receives the position (line and column nubers) of any syntax
+ * error within the source regular expression string. If this
+ * information is not wanted, pass NULL for this parameter.
+ * @param status Receives error detected by this function.
+ * @stable ICU 3.0
+ *
+ */
+U_STABLE URegularExpression * U_EXPORT2
+uregex_open( const UChar *pattern,
+ int32_t patternLength,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status);
+
+/**
+ * Open (compile) an ICU regular expression. 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 nubers) of any syntax
+ * error within the source regular expression string. If this
+ * information is not wanted, pass NULL for this parameter.
+ * @param status Receives error detected by this function.
+ *
+ * @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 termintated.
+ * @param flags Flags that alter the default matching behavior for
+ * the regular expression, UREGEX_CASE_INSENSITIVE, for
+ * example. For default behavior, set this parameter to zero.
+ * See <code>enum URegexpFlag</code>. All desired flags
+ * are bitwise-ORed together.
+ * @param pe Receives the position (line and column nubers) of any syntax
+ * error within the source regular expression string. If this
+ * information is not wanted, pass NULL for this parameter.
+ * @param status Receives errors detected by this function.
+ * @return The URegularExpression object representing the compiled
+ * pattern.
+ *
+ * @stable ICU 3.0
+ */
+#if !UCONFIG_NO_CONVERSION
+U_STABLE URegularExpression * U_EXPORT2
+uregex_openC( const char *pattern,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status);
+#endif
+
+
+
+/**
+ * Close the regular expression, recovering all resources (memory) it
+ * was holding.
+ *
+ * @param regexp The regular expression to be closed.
+ * @stable ICU 3.0
+ */
+U_STABLE void U_EXPORT2
+uregex_close(URegularExpression *regexp);
+
+#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 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);
+
+/**
+ * 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.
+ * @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.
+ * @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.
+ * @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.
+ * @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.
+ * @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.
+ * @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.
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uregex_setRegion64(URegularExpression *regexp,
+ int64_t regionStart,
+ int64_t regionLimit,
+ UErrorCode *status);
+
+/**
+ * Variation on uregex_setRegion to set the region without resetting the start index
+ * without resetting the position for subsequent matches.
+ * @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.
+ * @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.
+ * @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 desitnation buffer.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The length of the string resulting from the find
+ * and replace operation. In the event that the
+ * destination capacity is inadequate, the return value
+ * is still the full length of the untruncated string.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_replaceAll(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * Replaces 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 desitnation buffer.
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return The length of the string resulting from the find
+ * and replace operation. In the event that the
+ * destination capacity is inadequate, the return value
+ * is still the full length of the untruncated string.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_replaceFirst(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * 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.
+ * @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.
+ * <p>
+ * 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.
+ *
+ * Note: another choice for the design of this function would be to not
+ * copy the resulting fields at all, but to return indexes and
+ * lengths within the source text.
+ * Advantages would be
+ * o Faster. No Copying.
+ * o Nothing extra needed when field data may contain embedded NUL chars.
+ * o Less memory needed if working on large data.
+ * Disadvantages
+ * o Less consistent with C++ split, which copies into an
+ * array of UnicodeStrings.
+ * o No NUL termination, extracted fields would be less convenient
+ * to use in most cases.
+ * o Possible problems in the future, when support Unicode Normalization
+ * could cause the fields to not correspond exactly to
+ * a range of the source text.
+ *
+ * @param regexp The compiled regular expression.
+ * @param destBuf A (UChar *) buffer to receive the fields that
+ * are extracted from the input string. These
+ * field pointers will refer to positions within the
+ * destination buffer supplied by the caller. Any
+ * extra positions within the destFields array will be
+ * set to NULL.
+ * @param destCapacity The capacity of the destBuf.
+ * @param requiredCapacity The actual capacity required of the destBuf.
+ * If destCapacity is too small, requiredCapacity will return
+ * the total capacity required to hold all of the output, and
+ * a U_BUFFER_OVERFLOW_ERROR will be returned.
+ * @param destFields An array to be filled with the position of each
+ * of the extracted fields within destBuf.
+ * @param destFieldsCapacity The number of elements in the destFields array.
+ * If the number of fields found is less than destFieldsCapacity,
+ * the extra destFields elements are set to zero.
+ * If destFieldsCapacity is too small, the trailing part of the
+ * input, including any field delimiters, is treated as if it
+ * were the last field - it is copied to the destBuf, and
+ * its position is in the destBuf is stored in the last element
+ * of destFields. This behavior mimics that of Perl. It is not
+ * an error condition, and no error status is returned when all destField
+ * positions are used.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The number of fields into which the input string was split.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_split( URegularExpression *regexp,
+ UChar *destBuf,
+ int32_t destCapacity,
+ int32_t *requiredCapacity,
+ UChar *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status);
+
+
+ /**
+ * 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 avaliable 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 paramater, 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 paramater, 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.6/i18n/unicode/usearch.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/usearch.h
new file mode 100644
index 00000000000..2f3d563902b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unicode/usearch.h
@@ -0,0 +1,829 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2010 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 greater than <tt>position</tt> at which the string
+* text
+* matches the search pattern. The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* <p>
+* Search positions that may render incorrect results are highlighted in the
+* header comments. If position is less than or greater than the text range
+* for searching, an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+* @param strsrch search iterator data struct
+* @param position to start the search at
+* @param status for errors if it occurs
+* @return The character index of the first match following <tt>pos</tt>,
+* or <tt>USEARCH_DONE</tt> if there are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_following(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status);
+
+/**
+* Returns the last index in the target text at which it matches the search
+* pattern. The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>.
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The index of the first match, or <tt>USEARCH_DONE</tt> if there
+* are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_last(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Returns the first index less than <tt>position</tt> at which the string text
+* matches the search pattern. The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* <p>
+* Search positions that may render incorrect results are highlighted in the
+* header comments. If position is less than or greater than the text range
+* for searching, an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+* @param strsrch search iterator data struct
+* @param position index position the search is to begin at
+* @param status for errors if it occurs
+* @return The character index of the first match preceding <tt>pos</tt>,
+* or <tt>USEARCH_DONE</tt> if there are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_preceding(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status);
+
+/**
+* Returns the index of the next point at which the string text matches the
+* search pattern, starting from the current position.
+* The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The index of the next match after the current position, or
+* <tt>USEARCH_DONE</tt> if there are no more matches.
+* @see #usearch_first
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_next(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Returns the index of the previous point at which the string text matches
+* the search pattern, starting at the current position.
+* The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The index of the previous match before the current position,
+* or <tt>USEARCH_DONE</tt> if there are no more matches.
+* @see #usearch_last
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_previous(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Reset the iteration.
+* Search will begin at the start of the text string if a forward iteration
+* is initiated before a backwards iteration. Otherwise if a backwards
+* iteration is initiated before a forwards iteration, the search will begin
+* at the end of the text string.
+* @param strsrch search iterator data struct
+* @see #usearch_first
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_reset(UStringSearch *strsrch);
+
+/**
+ * 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.6/i18n/unicode/uspoof.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/uspoof.h
new file mode 100644
index 00000000000..7a218ca934b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/utmscale.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/utmscale.h
new file mode 100644
index 00000000000..472d776a62d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/utrans.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/utrans.h
new file mode 100644
index 00000000000..5ef035fdd06
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unicode/vtzone.h b/Build/source/libs/icu/icu-4.6/i18n/unicode/vtzone.h
new file mode 100644
index 00000000000..724da7e289b
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/unum.cpp b/Build/source/libs/icu/icu-4.6/i18n/unum.cpp
new file mode 100644
index 00000000000..4e016775bdc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/unum.cpp
@@ -0,0 +1,947 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2010, 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 0;
+ }
+
+ UNumberFormat *retVal = 0;
+
+ switch(style) {
+ case UNUM_DECIMAL:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_CURRENCY:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_PERCENT:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_SCIENTIFIC:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createScientificInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createScientificInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_PATTERN_DECIMAL: {
+ UParseError tErr;
+ /* UnicodeString can handle the case when patternLength = -1. */
+ const UnicodeString pat(pattern, patternLength);
+ DecimalFormatSymbols *syms = 0;
+
+ if(parseErr==NULL){
+ parseErr = &tErr;
+ }
+
+ if(locale == 0)
+ syms = new DecimalFormatSymbols(*status);
+ else
+ syms = new DecimalFormatSymbols(Locale(locale), *status);
+
+ if(syms == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ if (U_FAILURE(*status)) {
+ delete syms;
+ return 0;
+ }
+
+ retVal = (UNumberFormat*)new DecimalFormat(pat, syms, *parseErr, *status);
+ if(retVal == 0) {
+ delete syms;
+ }
+ } break;
+
+#if U_HAVE_RBNF
+ case UNUM_PATTERN_RULEBASED: {
+ UParseError tErr;
+ /* UnicodeString can handle the case when patternLength = -1. */
+ const UnicodeString pat(pattern, patternLength);
+
+ if(parseErr==NULL){
+ parseErr = &tErr;
+ }
+
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
+ } break;
+
+ case UNUM_SPELLOUT:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
+ break;
+
+ case UNUM_ORDINAL:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
+ break;
+
+ case UNUM_DURATION:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
+ break;
+
+ case UNUM_NUMBERING_SYSTEM:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
+ break;
+#endif
+
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ if(retVal == 0 && U_SUCCESS(*status)) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ return retVal;
+}
+
+U_CAPI void U_EXPORT2
+unum_close(UNumberFormat* fmt)
+{
+ delete (NumberFormat*) fmt;
+}
+
+U_CAPI UNumberFormat* U_EXPORT2
+unum_clone(const UNumberFormat *fmt,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status))
+ return 0;
+
+ Format *res = 0;
+ 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);
+ 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;
+ }
+ } else {
+ const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+ U_ASSERT(rbnf != NULL);
+ if (attr == UNUM_LENIENT_PARSE) {
+#if !UCONFIG_NO_COLLATION
+ return rbnf->isLenient();
+#endif
+ }
+ }
+
+ return -1;
+}
+
+U_CAPI void U_EXPORT2
+unum_setAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ int32_t newValue)
+{
+ NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+ 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;
+ }
+ } else {
+ RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
+ U_ASSERT(rbnf != NULL);
+ if (attr == UNUM_LENIENT_PARSE) {
+#if !UCONFIG_NO_COLLATION
+ rbnf->setLenient((UBool)newValue);
+#endif
+ }
+ }
+}
+
+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 || (uint16_t)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 || (uint16_t)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.6/i18n/uregex.cpp b/Build/source/libs/icu/icu-4.6/i18n/uregex.cpp
new file mode 100644
index 00000000000..c2249eb156a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uregex.cpp
@@ -0,0 +1,1910 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2010, 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, UErrorCode *status, UBool requiresText = TRUE) {
+ 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, &status, FALSE) == 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, status, FALSE) == 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, status, FALSE) == 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, status, FALSE) == 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, status, FALSE) == 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, status, FALSE) == 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, status, FALSE) == 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, status, FALSE) == FALSE) {
+ return dest;
+ }
+ return regexp->fMatcher->getInput(dest, *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, 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, 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, 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, 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, status, FALSE) == 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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. We're done.
+ break;
+ }
+
+ }
+ else
+ {
+ // We ran off the end of the input while looking for the next delimiter.
+ // All the remaining text goes into the current output string.
+ destFields[i] = &destBuf[destIdx];
+ 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, 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.6/i18n/uregexc.cpp b/Build/source/libs/icu/icu-4.6/i18n/uregexc.cpp
new file mode 100644
index 00000000000..6590020661e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/usearch.cpp b/Build/source/libs/icu/icu-4.6/i18n/usearch.cpp
new file mode 100644
index 00000000000..95e3f86bbb4
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/usearch.cpp
@@ -0,0 +1,4749 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2010 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 !BOYER_MOORE
+ if (search->matchedIndex != USEARCH_DONE) {
+ if (search->isOverlap) {
+ ucol_setOffset(strsrch->textIter, search->matchedIndex + search->matchedLength - 2, status);
+ }
+ }
+#endif
+
+ 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 50
+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.CELength+10;
+ 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 FALSE;
+ }
+
+ // 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 FALSE;
+ }
+
+ // 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 FALSE;
+#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 (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 *firstCEI = ceb.get(targetIx);
+ 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.
+ if (strsrch->search->elementComparisonType == 0) {
+ const CEI *nextCEI = ceb.get(targetIx + targetIxOffset);
+ maxLimit = nextCEI->lowIndex;
+ if (nextCEI->lowIndex == nextCEI->highIndex && nextCEI->ce != UCOL_PROCESSED_NULLORDER) {
+ found = FALSE;
+ }
+ } else {
+ const CEI *nextCEI;
+ 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) {
+ 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;
+ // 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);
+ const CEI *lastCEI = ceb.getPrevious(targetIx);
+ const CEI *nextCEI = targetIx > 0? ceb.getPrevious(targetIx - 1) : NULL;
+
+ mStart = firstCEI->lowIndex;
+ minLimit = lastCEI->lowIndex;
+ maxLimit = targetIx > 0? nextCEI->lowIndex : lastCEI->highIndex;
+
+ // 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.
+ if (targetIx >= 1) {
+ if (nextCEI->lowIndex == nextCEI->highIndex && nextCEI->ce != UCOL_PROCESSED_NULLORDER) {
+ found = FALSE;
+ }
+ }
+
+
+ // 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;
+ }
+
+ // Advance the match end position to the first acceptable match boundary.
+ // This advances the index over any combining charcters.
+ mLimit = maxLimit;
+ if (/*targetIx > 0 &&*/ minLimit < maxLimit) {
+ 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;
+ }
+
+ // Make sure the end of the match is on a break boundary
+ 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;
+}
+
+
+
+
+// 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 = 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 = 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.6/i18n/uspoof.cpp b/Build/source/libs/icu/icu-4.6/i18n/uspoof.cpp
new file mode 100644
index 00000000000..2cb785b7b91
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uspoof.cpp
@@ -0,0 +1,827 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2009, 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
+
+
+#include <stdio.h> // debug
+
+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 NFKD input
+ NFKDBuffer normalizedInput(text, length, *status);
+ const UChar *nfkdText = normalizedInput.getBuffer();
+ int32_t nfkdLength = 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<length ;) {
+ U16_NEXT(nfkdText, i, nfkdLength, 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;
+ 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(nfkdText, nfkdLength, &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;
+ }
+
+ // NFKD transform of the user supplied input
+
+ UChar nfkdStackBuf[USPOOF_STACK_BUFFER_SIZE];
+ UChar *nfkdInput = nfkdStackBuf;
+ int32_t normalizedLen = unorm_normalize(
+ s, length, UNORM_NFKD, 0, nfkdInput, USPOOF_STACK_BUFFER_SIZE, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ nfkdInput = (UChar *)uprv_malloc((normalizedLen+1)*sizeof(UChar));
+ if (nfkdInput == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *status = U_ZERO_ERROR;
+ normalizedLen = unorm_normalize(s, length, UNORM_NFKD, 0,
+ nfkdInput, normalizedLen+1, status);
+ }
+ if (U_FAILURE(*status)) {
+ if (nfkdInput != nfkdStackBuf) {
+ uprv_free(nfkdInput);
+ }
+ 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 NFKD normalized input string
+ // Accumulate the skeleton, possibly unnormalized, in a UnicodeString.
+ int32_t inputIndex = 0;
+ UnicodeString skelStr;
+ while (inputIndex < normalizedLen) {
+ UChar32 c;
+ U16_NEXT(nfkdInput, inputIndex, normalizedLen, c);
+ int32_t replaceLen = This->confusableLookup(c, tableMask, buf);
+ skelStr.append(buf, replaceLen);
+ }
+
+ if (nfkdInput != nfkdStackBuf) {
+ uprv_free(nfkdInput);
+ }
+
+ const UChar *result = skelStr.getBuffer();
+ int32_t resultLen = skelStr.length();
+ UChar *normedResult = NULL;
+
+ // Check the skeleton for NFKD, normalize it if needed.
+ // Unnormalized results should be very rare.
+ if (!unorm_isNormalized(result, resultLen, UNORM_NFKD, status)) {
+ normalizedLen = unorm_normalize(result, resultLen, UNORM_NFKD, 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_NFKD, 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.6/i18n/uspoof_build.cpp b/Build/source/libs/icu/icu-4.6/i18n/uspoof_build.cpp
new file mode 100644
index 00000000000..681282e0a89
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/uspoof_conf.cpp b/Build/source/libs/icu/icu-4.6/i18n/uspoof_conf.cpp
new file mode 100644
index 00000000000..7a8f2070764
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uspoof_conf.cpp
@@ -0,0 +1,600 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2010, 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;
+ }
+ 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 ... "
+ fParseLine = uregex_openC(
+ "(?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
+ "|^(.*?)$", // OR match any line, which catches illegal lines.
+ 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.
+ fParseHexNum = uregex_openC("\\s*([0-9A-F]+)", 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.6/i18n/uspoof_conf.h b/Build/source/libs/icu/icu-4.6/i18n/uspoof_conf.h
new file mode 100644
index 00000000000..d23e6d55db7
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uspoof_conf.h
@@ -0,0 +1,132 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2009, 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 key);
+
+ // 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.6/i18n/uspoof_impl.cpp b/Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.cpp
new file mode 100644
index 00000000000..3cc69b81aba
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.cpp
@@ -0,0 +1,962 @@
+/*
+**********************************************************************
+* Copyright (C) 2008-2009, 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(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fMagic = USPOOF_MAGIC;
+ fSpoofData = data;
+ fChecks = USPOOF_ALL_CHECKS;
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
+ if (allowedCharsSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ allowedCharsSet->freeze();
+ fAllowedCharsSet = allowedCharsSet;
+ fAllowedLocales = uprv_strdup("");
+}
+
+
+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();
+ }
+ fCheckMask = src.fCheckMask;
+ 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 NFKD
+// 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;
+ fCheckMask &= ~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;
+ fCheckMask |= 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;
+ }
+ 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;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// NFKDBuffer Implementation.
+//
+//-----------------------------------------------------------------------------
+
+NFKDBuffer::NFKDBuffer(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_NFKD, 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_NFKD, 0,
+ fNormalizedText, fNormalizedTextLength+1, &status);
+ }
+ }
+}
+
+
+NFKDBuffer::~NFKDBuffer() {
+ if (fNormalizedText != fSmallBuf) {
+ uprv_free(fNormalizedText);
+ }
+ fNormalizedText = 0;
+}
+
+const UChar *NFKDBuffer::getBuffer() {
+ return fNormalizedText;
+}
+
+int32_t NFKDBuffer::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) * 4;
+ 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
+ // int32_t 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);
+ ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8, &outputDH->fLength, status);
+
+ return totalSize;
+}
+
+#endif
+
+
diff --git a/Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.h b/Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.h
new file mode 100644
index 00000000000..175e00ee924
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uspoof_impl.h
@@ -0,0 +1,411 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2009, 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
+
+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;
+
+
+ // WholeScript and MixedScript check implementation.
+ //
+ ScriptSet *WholeScriptCheck(const UChar *text, int32_t length, 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;
+
+ int32_t fCheckMask; // Spoof table selector. f(Check Type)
+
+ 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];
+};
+
+
+
+
+//-------------------------------------------------------------------------------
+//
+// NFKDBuffer A little class to handle the NFKD 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 NFKDBuffer: public UMemory {
+public:
+ NFKDBuffer(const UChar *text, int32_t length, UErrorCode &status);
+ ~NFKDBuffer();
+ 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're 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; // (0x8345fdef)
+ 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
+
+/**
+ * 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.6/i18n/uspoof_wsconf.cpp b/Build/source/libs/icu/icu-4.6/i18n/uspoof_wsconf.cpp
new file mode 100644
index 00000000000..37232440746
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/uspoof_wsconf.cpp
@@ -0,0 +1,435 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 2008-2009, 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);
+
+
+ // 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_openC(parseExp, 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++;
+ UChar line[200];
+ uregex_group(parseRegexp, 0, line, 200, &status);
+ 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.6/i18n/uspoof_wsconf.h b/Build/source/libs/icu/icu-4.6/i18n/uspoof_wsconf.h
new file mode 100644
index 00000000000..2b633152368
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/usrchimp.h b/Build/source/libs/icu/icu-4.6/i18n/usrchimp.h
new file mode 100644
index 00000000000..986db33699f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/utmscale.c b/Build/source/libs/icu/icu-4.6/i18n/utmscale.c
new file mode 100644
index 00000000000..33f5d9212d0
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/utrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/utrans.cpp
new file mode 100644
index 00000000000..16a09bdcb6a
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/vtzone.cpp b/Build/source/libs/icu/icu-4.6/i18n/vtzone.cpp
new file mode 100644
index 00000000000..51a6a81ef46
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/vzone.cpp b/Build/source/libs/icu/icu-4.6/i18n/vzone.cpp
new file mode 100644
index 00000000000..3aa2dbbebcc
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/vzone.h b/Build/source/libs/icu/icu-4.6/i18n/vzone.h
new file mode 100644
index 00000000000..c81413cae0f
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/vzone.h
@@ -0,0 +1,386 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, 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.
+ * @stable ICU 2.4
+ */
+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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT UClassID U_EXPORT2
+vzone_getDynamicClassID(VZone* zone);
+
+#endif // __VZONE_H
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/windtfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/windtfmt.cpp
new file mode 100644
index 00000000000..8fedabd6753
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/windtfmt.h b/Build/source/libs/icu/icu-4.6/i18n/windtfmt.h
new file mode 100644
index 00000000000..5f6e2dab494
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/windtfmt.h
@@ -0,0 +1,149 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2009, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINDTFMT.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINDTFMT
+#define __WINDTFMT
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/datefmt.h"
+#include "unicode/calendar.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+
+/**
+ * \file
+ * \brief C++ API: Format dates using Windows API.
+ */
+
+U_CDECL_BEGIN
+// Forward declarations for Windows types...
+typedef struct _SYSTEMTIME SYSTEMTIME;
+typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+class Win32DateFormat : public DateFormat
+{
+public:
+ Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status);
+
+ Win32DateFormat(const Win32DateFormat &other);
+
+ virtual ~Win32DateFormat();
+
+ virtual Format *clone(void) const;
+
+ Win32DateFormat &operator=(const Win32DateFormat &other);
+
+ UnicodeString &format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const;
+
+ UnicodeString& format(UDate date, UnicodeString& appendTo) const;
+
+ void parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const;
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used. The caller should
+ * not delete the Calendar object after it is adopted by this call.
+ *
+ * @param calendarToAdopt Calendar object to be adopted.
+ * @draft ICU 3.6
+ */
+ virtual void adoptCalendar(Calendar* calendarToAdopt);
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used.
+ *
+ * @param newCalendar Calendar object to be set.
+ *
+ * @draft ICU 3.6
+ */
+ virtual void setCalendar(const Calendar& newCalendar);
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object. The caller
+ * no longer owns the TimeZone object and should not delete it after this call.
+ *
+ * @param zoneToAdopt the TimeZone to be adopted.
+ *
+ * @draft ICU 3.6
+ */
+ virtual void adoptTimeZone(TimeZone* zoneToAdopt);
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object.
+ * @param zone the new time zone.
+ *
+ * @draft ICU 3.6
+ */
+ virtual void setTimeZone(const TimeZone& zone);
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.6
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.6
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ void formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const;
+ void formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const;
+
+ UnicodeString setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const TimeZone &zone) const;
+ UnicodeString* 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.6/i18n/winnmfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/winnmfmt.cpp
new file mode 100644
index 00000000000..4207c52e7e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/winnmfmt.h b/Build/source/libs/icu/icu-4.6/i18n/winnmfmt.h
new file mode 100644
index 00000000000..9b737f8ab79
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/winnmfmt.h
@@ -0,0 +1,168 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINNMFMT.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINNMFMT
+#define __WINNMFMT
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#include "unicode/format.h"
+#include "unicode/datefmt.h"
+#include "unicode/calendar.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C++ API: Format numbers using Windows API.
+ */
+
+U_NAMESPACE_BEGIN
+
+union FormatInfo;
+
+class Win32NumberFormat : public NumberFormat
+{
+public:
+ Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status);
+
+ Win32NumberFormat(const Win32NumberFormat &other);
+
+ virtual ~Win32NumberFormat();
+
+ virtual Format *clone(void) const;
+
+ Win32NumberFormat &operator=(const Win32NumberFormat &other);
+
+ /**
+ * Format a double number. Concrete subclasses must implement
+ * these pure virtual methods.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.6
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Format a long number. Concrete subclasses must implement
+ * these pure virtual methods.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.6
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an int64 number.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.6
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+// Use the default behavior for the following.
+// virtual UnicodeString &format(double number, UnicodeString &appendTo) const;
+// virtual UnicodeString &format(int32_t number, UnicodeString &appendTo) const;
+// virtual UnicodeString &format(int64_t number, UnicodeString &appendTo) const;
+
+ virtual void parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const;
+
+ /**
+ * Sets the maximum number of digits allowed in the fraction portion of a
+ * number. maximumFractionDigits must be >= minimumFractionDigits. If the
+ * new value for maximumFractionDigits is less than the current value
+ * of minimumFractionDigits, then minimumFractionDigits will also be set to
+ * the new value.
+ * @param newValue the new value to be set.
+ * @see getMaximumFractionDigits
+ * @draft ICU 3.6
+ */
+ virtual void setMaximumFractionDigits(int32_t newValue);
+
+ /**
+ * Sets the minimum number of digits allowed in the fraction portion of a
+ * number. minimumFractionDigits must be &lt;= maximumFractionDigits. If the
+ * new value for minimumFractionDigits exceeds the current value
+ * of maximumFractionDigits, then maximumIntegerDigits will also be set to
+ * the new value
+ * @param newValue the new value to be set.
+ * @see getMinimumFractionDigits
+ * @draft ICU 3.6
+ */
+ virtual void setMinimumFractionDigits(int32_t newValue);
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ UnicodeString &format(int32_t numDigits, UnicodeString &appendTo, wchar_t *format, ...) const;
+
+ UBool fCurrency;
+ int32_t fLCID;
+ FormatInfo *fFormatInfo;
+ UBool fFractionDigitsSet;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
+#endif // __WINNMFMT
diff --git a/Build/source/libs/icu/icu-4.6/i18n/wintzimpl.cpp b/Build/source/libs/icu/icu-4.6/i18n/wintzimpl.cpp
new file mode 100644
index 00000000000..fb7de50a812
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/wintzimpl.h b/Build/source/libs/icu/icu-4.6/i18n/wintzimpl.h
new file mode 100644
index 00000000000..e7083e9226e
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/zonemeta.cpp b/Build/source/libs/icu/icu-4.6/i18n/zonemeta.cpp
new file mode 100644
index 00000000000..65291e688ef
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/zonemeta.cpp
@@ -0,0 +1,650 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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"
+
+static UMTX gZoneMetaLock = NULL;
+
+// Metazone mapping table
+static UHashtable *gOlsonToMeta = NULL;
+static UBool gOlsonToMetaInitialized = 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 (gOlsonToMeta != NULL) {
+ uhash_close(gOlsonToMeta);
+ gOlsonToMeta = NULL;
+ }
+ gOlsonToMetaInitialized = 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;
+}
+
+UnicodeString& U_EXPORT2
+ZoneMeta::getCanonicalSystemID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) {
+ int32_t len = tzid.length();
+ if ( len >= ZID_KEY_MAX ) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ systemID.remove();
+ return systemID;
+ }
+
+ char id[ZID_KEY_MAX];
+ 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 = ':';
+ }
+ }
+
+
+ UErrorCode tmpStatus = U_ZERO_ERROR;
+ 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)) {
+ // direct map found
+ systemID.setTo(tzid);
+ ures_close(rb);
+ ures_close(top);
+ return systemID;
+ }
+
+ // 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 *alias = ures_getStringByKey(rb,id,NULL,&tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // alias found
+ ures_close(rb);
+ ures_close(top);
+ systemID.setTo(alias);
+ return systemID;
+ }
+
+ // Dereference the input ID using the tz data
+ const UChar *derefer = TimeZone::dereferOlsonLink(tzid);
+ if (derefer == NULL) {
+ systemID.remove();
+ 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;
+ const UChar *alias = ures_getStringByKey(rb,id,NULL,&tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // alias found
+ systemID.setTo(alias);
+ } else {
+ systemID.setTo(derefer);
+ }
+ }
+
+ ures_close(rb);
+ ures_close(top);
+ return systemID;
+}
+
+UnicodeString& U_EXPORT2
+ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
+ const UChar *region = TimeZone::getRegion(tzid);
+ if (u_strcmp(gWorld, region) != 0) {
+ canonicalCountry.setTo(region, -1);
+ } else {
+ canonicalCountry.remove();
+ }
+ 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 (u_strcmp(gWorld, region) == 0) {
+ // special case - "001"
+ country.remove();
+ 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.remove();
+ 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::createEnumeration(buf);
+ int32_t idsLen = ids->count(status);
+ if (U_SUCCESS(status) && idsLen > 1) {
+ // multiple zones are available for the region
+ UnicodeString canonical, tmp;
+ const UnicodeString *id = ids->snext(status);
+ getCanonicalSystemID(*id, canonical, status);
+ if (U_SUCCESS(status)) {
+ // check if there are any other canonical zone in the group
+ while ((id = ids->snext(status))!=NULL) {
+ getCanonicalSystemID(*id, tmp, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ if (canonical != tmp) {
+ // another canonical zone was found
+ multiZones = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ 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.remove();
+ } 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.remove();
+ }
+ return result;
+}
+
+const UVector* U_EXPORT2
+ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
+ UErrorCode status = U_ZERO_ERROR;
+ UChar tzidUChars[ZID_KEY_MAX];
+ tzid.extract(tzidUChars, ZID_KEY_MAX, 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);
+ TimeZone::getCanonicalID(tzid, canonicalID, status);
+
+ if (U_SUCCESS(status)) {
+ char tzKey[ZID_KEY_MAX];
+ canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV);
+
+ // 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.remove();
+ return result;
+ }
+
+ keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX, US_INV);
+
+ 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) {
+ region.extract(0, region.length(), keyBuf, ZID_KEY_MAX, US_INV);
+ 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.remove();
+ } else {
+ result.setTo(tzid, tzidLen);
+ }
+
+ return result;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/zonemeta.h b/Build/source/libs/icu/icu-4.6/i18n/zonemeta.h
new file mode 100644
index 00000000000..ead9f35214c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/zonemeta.h
@@ -0,0 +1,68 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, 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 U_I18N_API ZoneMeta {
+public:
+ /**
+ * Return the canonical id for this system tzid, which might be the id itself.
+ * If the given system tzid is not know, U_ILLEGAL_ARGUMENT_ERROR is set in the status.
+ */
+ static UnicodeString& U_EXPORT2 getCanonicalSystemID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status);
+
+ /**
+ * 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);
+
+private:
+ ZoneMeta(); // Prevent construction.
+ static UVector* createMetazoneMappings(const UnicodeString &tzid);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif // ZONEMETA_H
diff --git a/Build/source/libs/icu/icu-4.6/i18n/zrule.cpp b/Build/source/libs/icu/icu-4.6/i18n/zrule.cpp
new file mode 100644
index 00000000000..82c31169f6c
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/zrule.h b/Build/source/libs/icu/icu-4.6/i18n/zrule.h
new file mode 100644
index 00000000000..04f7abf3184
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/zrule.h
@@ -0,0 +1,302 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, 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.
+ * @draft ICU 4.4
+ */
+struct ZRule;
+typedef struct ZRule ZRule;
+
+/**
+ * An InitialTimeZoneRule. Use the izrule_* API to manipulate. Create with
+ * izrule_open*, and destroy with izrule_close.
+ * @draft ICU 4.4
+ */
+struct IZRule;
+typedef struct IZRule IZRule;
+
+/**
+ * An AnnualTimeZoneRule. Use the azrule_* API to manipulate. Create with
+ * azrule_open*, and destroy with azrule_close.
+ * @draft ICU 4.4
+ */
+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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT UClassID U_EXPORT2
+izrule_getDynamicClassID(IZRule* rule);
+
+#endif
+
+#endif
diff --git a/Build/source/libs/icu/icu-4.6/i18n/zstrfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/zstrfmt.cpp
new file mode 100644
index 00000000000..acd3546e281
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/zstrfmt.cpp
@@ -0,0 +1,2228 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "zstrfmt.h"
+
+#include "unicode/ustring.h"
+#include "unicode/putil.h"
+#include "unicode/msgfmt.h"
+#include "unicode/basictz.h"
+#include "unicode/simpletz.h"
+#include "unicode/rbtz.h"
+#include "unicode/vtzone.h"
+
+#include "uvector.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "uresimp.h"
+#include "zonemeta.h"
+#include "olsontz.h"
+#include "umutex.h"
+#include "ucln_in.h"
+#include "uassert.h"
+#include "ureslocs.h"
+
+/**
+ * global ZoneStringFormatCache stuffs
+ */
+static UMTX gZSFCacheLock = NULL;
+static U_NAMESPACE_QUALIFIER ZSFCache *gZoneStringFormatCache = NULL;
+
+U_CDECL_BEGIN
+/**
+ * ZoneStringFormatCache cleanup callback func
+ */
+static UBool U_CALLCONV zoneStringFormat_cleanup(void)
+{
+ umtx_destroy(&gZSFCacheLock);
+ if (gZoneStringFormatCache != NULL) {
+ delete gZoneStringFormatCache;
+ gZoneStringFormatCache = NULL;
+ }
+ gZoneStringFormatCache = NULL;
+ return TRUE;
+}
+
+/**
+ * Deleter for ZoneStringInfo
+ */
+static void U_CALLCONV
+deleteZoneStringInfo(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER ZoneStringInfo*)obj;
+}
+
+/**
+ * Deleter for ZoneStrings
+ */
+static void U_CALLCONV
+deleteZoneStrings(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER ZoneStrings*)obj;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+#define ZID_KEY_MAX 128
+
+static const char gCountriesTag[] = "Countries";
+static const char gZoneStringsTag[] = "zoneStrings";
+static const char gShortGenericTag[] = "sg";
+static const char gShortStandardTag[] = "ss";
+static const char gShortDaylightTag[] = "sd";
+static const char gLongGenericTag[] = "lg";
+static const char gLongStandardTag[] = "ls";
+static const char gLongDaylightTag[] = "ld";
+static const char gExemplarCityTag[] = "ec";
+static const char gCommonlyUsedTag[] = "cu";
+static const char gFallbackFormatTag[] = "fallbackFormat";
+static const char gRegionFormatTag[] = "regionFormat";
+
+#define MZID_PREFIX_LEN 5
+static const char gMetazoneIdPrefix[] = "meta:";
+
+#define MAX_METAZONES_PER_ZONE 10
+
+static const UChar gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
+static const UChar gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
+static const UChar gCommonlyUsedTrue[] = {0x31, 0x00}; // "1"
+
+static const double kDstCheckRange = (double)184*U_MILLIS_PER_DAY;
+
+static int32_t
+getTimeZoneTranslationTypeIndex(TimeZoneTranslationType type) {
+ int32_t typeIdx = 0;
+ switch (type) {
+ case LOCATION:
+ typeIdx = ZSIDX_LOCATION;
+ break;
+ case GENERIC_LONG:
+ typeIdx = ZSIDX_LONG_GENERIC;
+ break;
+ case GENERIC_SHORT:
+ typeIdx = ZSIDX_SHORT_GENERIC;
+ break;
+ case STANDARD_LONG:
+ typeIdx = ZSIDX_LONG_STANDARD;
+ break;
+ case STANDARD_SHORT:
+ typeIdx = ZSIDX_SHORT_STANDARD;
+ break;
+ case DAYLIGHT_LONG:
+ typeIdx = ZSIDX_LONG_DAYLIGHT;
+ break;
+ case DAYLIGHT_SHORT:
+ typeIdx = ZSIDX_SHORT_DAYLIGHT;
+ break;
+ }
+ return typeIdx;
+}
+
+static int32_t
+getTimeZoneTranslationType(TimeZoneTranslationTypeIndex typeIdx) {
+ int32_t type = 0;
+ switch (typeIdx) {
+ case ZSIDX_LOCATION:
+ type = LOCATION;
+ break;
+ case ZSIDX_LONG_GENERIC:
+ type = GENERIC_LONG;
+ break;
+ case ZSIDX_SHORT_GENERIC:
+ type = GENERIC_SHORT;
+ break;
+ case ZSIDX_LONG_STANDARD:
+ type = STANDARD_LONG;
+ break;
+ case ZSIDX_SHORT_STANDARD:
+ type = STANDARD_SHORT;
+ break;
+ case ZSIDX_LONG_DAYLIGHT:
+ type = DAYLIGHT_LONG;
+ break;
+ case ZSIDX_COUNT:
+ case ZSIDX_SHORT_DAYLIGHT:
+ type = DAYLIGHT_SHORT;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+#define DEFAULT_CHARACTERNODE_CAPACITY 1
+
+// ----------------------------------------------------------------------------
+void CharacterNode::clear() {
+ uprv_memset(this, 0, sizeof(*this));
+}
+
+void CharacterNode::deleteValues() {
+ if (fValues == NULL) {
+ // Do nothing.
+ } else if (!fHasValuesVector) {
+ deleteZoneStringInfo(fValues);
+ } else {
+ delete (UVector *)fValues;
+ }
+}
+
+void
+CharacterNode::addValue(void *value, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ deleteZoneStringInfo(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(deleteZoneStringInfo, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status);
+ if (U_FAILURE(status)) {
+ deleteZoneStringInfo(value);
+ return;
+ }
+ values->addElement(fValues, status);
+ fValues = values;
+ fHasValuesVector = TRUE;
+ }
+ // Add the new value.
+ ((UVector *)fValues)->addElement(value, status);
+ }
+}
+
+//----------------------------------------------------------------------------
+// Virtual destructor to avoid warning
+TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){
+}
+
+// ----------------------------------------------------------------------------
+TextTrieMap::TextTrieMap(UBool ignoreCase)
+: fIgnoreCase(ignoreCase), fNodes(NULL), fNodesCapacity(0), fNodesCount(0),
+ fLazyContents(NULL), fIsEmpty(TRUE) {
+}
+
+TextTrieMap::~TextTrieMap() {
+ int32_t index;
+ for (index = 0; index < fNodesCount; ++index) {
+ fNodes[index].deleteValues();
+ }
+ uprv_free(fNodes);
+ if (fLazyContents != NULL) {
+ for (int32_t i=0; i<fLazyContents->size(); i+=2) {
+ ZoneStringInfo *zsinf = (ZoneStringInfo *)fLazyContents->elementAt(i+1);
+ delete zsinf;
+ }
+ 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, ZSFStringPool &sp, 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 *>(sp.get(key, status));
+ 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, 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);
+ }
+}
+
+// ----------------------------------------------------------------------------
+ZoneStringInfo::ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
+ TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status)
+: fType(type) {
+ fId = sp.get(id, status);
+ fStr = sp.get(str, status);
+}
+
+ZoneStringInfo::~ZoneStringInfo() {
+}
+
+
+// ----------------------------------------------------------------------------
+ZoneStringSearchResultHandler::ZoneStringSearchResultHandler(UErrorCode &status)
+: fResults(status)
+{
+ clear();
+}
+
+ZoneStringSearchResultHandler::~ZoneStringSearchResultHandler() {
+ clear();
+}
+
+UBool
+ZoneStringSearchResultHandler::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++) {
+ ZoneStringInfo *zsinfo = (ZoneStringInfo*)node->getValue(i);
+ if (zsinfo == NULL) {
+ break;
+ }
+ // Update the results
+ UBool foundType = FALSE;
+ for (int32_t j = 0; j < fResults.size(); j++) {
+ ZoneStringInfo *tmp = (ZoneStringInfo*)fResults.elementAt(j);
+ if (zsinfo->fType == tmp->fType) {
+ int32_t lenidx = getTimeZoneTranslationTypeIndex(tmp->fType);
+ if (matchLength > fMatchLen[lenidx]) {
+ // Same type, longer match
+ fResults.setElementAt(zsinfo, j);
+ fMatchLen[lenidx] = matchLength;
+ }
+ foundType = TRUE;
+ break;
+ }
+ }
+ if (!foundType) {
+ // not found in the current list
+ fResults.addElement(zsinfo, status);
+ fMatchLen[getTimeZoneTranslationTypeIndex(zsinfo->fType)] = matchLength;
+ }
+ }
+ }
+ return TRUE;
+}
+
+int32_t
+ZoneStringSearchResultHandler::countMatches(void) {
+ return fResults.size();
+}
+
+const ZoneStringInfo*
+ZoneStringSearchResultHandler::getMatch(int32_t index, int32_t &matchLength) {
+ ZoneStringInfo *zsinfo = NULL;
+ if (index < fResults.size()) {
+ zsinfo = (ZoneStringInfo*)fResults.elementAt(index);
+ matchLength = fMatchLen[getTimeZoneTranslationTypeIndex(zsinfo->fType)];
+ }
+ return zsinfo;
+}
+
+void
+ZoneStringSearchResultHandler::clear(void) {
+ fResults.removeAllElements();
+ for (int32_t i = 0; i < (int32_t)(sizeof(fMatchLen)/sizeof(fMatchLen[0])); i++) {
+ fMatchLen[i] = 0;
+ }
+}
+
+// Mutex for protecting the lazy load of a zone ID (or a full load) to ZoneStringFormat structures.
+static UMTX ZoneStringFormatMutex;
+
+
+// ----------------------------------------------------------------------------
+ZoneStringFormat::ZoneStringFormat(const UnicodeString* const* strings,
+ int32_t rowCount, int32_t columnCount, UErrorCode &status)
+: fLocale(""),
+ fTzidToStrings(NULL),
+ fMzidToStrings(NULL),
+ fZoneStringsTrie(TRUE),
+ fStringPool(status),
+ fZoneStringsArray(NULL),
+ fMetazoneItem(NULL),
+ fZoneItem(NULL),
+ fIsFullyLoaded(FALSE)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fLocale.setToBogus();
+ if (strings == NULL || columnCount <= 0 || rowCount <= 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ fTzidToStrings = uhash_open(uhash_hashUChars, // key hash function
+ uhash_compareUChars, // key comparison function
+ NULL, // Value comparison function
+ &status);
+ fMzidToStrings = uhash_open(uhash_hashUChars,
+ uhash_compareUChars,
+ NULL,
+ &status);
+
+ uhash_setValueDeleter(fTzidToStrings, deleteZoneStrings);
+ uhash_setValueDeleter(fMzidToStrings, deleteZoneStrings);
+
+ for (int32_t row = 0; row < rowCount; row++) {
+ if (strings[row][0].isEmpty()) {
+ continue;
+ }
+ UnicodeString *names = new UnicodeString[ZSIDX_COUNT];
+ for (int32_t col = 1; col < columnCount; col++) {
+ if (!strings[row][col].isEmpty()) {
+ int32_t typeIdx = -1;
+ switch (col) {
+ case 1:
+ typeIdx = ZSIDX_LONG_STANDARD;
+ break;
+ case 2:
+ typeIdx = ZSIDX_SHORT_STANDARD;
+ break;
+ case 3:
+ typeIdx = ZSIDX_LONG_DAYLIGHT;
+ break;
+ case 4:
+ typeIdx = ZSIDX_SHORT_DAYLIGHT;
+ break;
+ case 5:
+ typeIdx = ZSIDX_LOCATION;
+ break;
+ case 6:
+ typeIdx = ZSIDX_LONG_GENERIC;
+ break;
+ case 7:
+ typeIdx = ZSIDX_SHORT_GENERIC;
+ break;
+ }
+ if (typeIdx != -1) {
+ names[typeIdx].setTo(strings[row][col]);
+
+ // Put the name into the trie
+ int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)typeIdx);
+ ZoneStringInfo *zsinf = new ZoneStringInfo(strings[row][0],
+ strings[row][col],
+ (TimeZoneTranslationType)type,
+ fStringPool,
+ status);
+ fZoneStringsTrie.put(strings[row][col], zsinf, fStringPool, status);
+ if (U_FAILURE(status)) {
+ delete zsinf;
+ goto error_cleanup;
+ }
+ }
+ }
+ }
+ // Note: ZoneStrings constructor adopts and delete the names array.
+ ZoneStrings *zstrings = new ZoneStrings(names, ZSIDX_COUNT, TRUE, NULL, 0, 0,
+ fStringPool, status);
+ UChar *utzid = const_cast<UChar *>(fStringPool.get(strings[row][0], status));
+ uhash_put(fTzidToStrings, utzid, zstrings, &status);
+ if (U_FAILURE(status)) {
+ delete zstrings;
+ goto error_cleanup;
+ }
+ }
+ fStringPool.freeze();
+ fIsFullyLoaded = TRUE;
+ return;
+
+error_cleanup:
+ return;
+}
+
+ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
+: fLocale(locale),
+ fTzidToStrings(NULL),
+ fMzidToStrings(NULL),
+ fZoneStringsTrie(TRUE),
+ fStringPool(status),
+ fZoneStringsArray(NULL),
+ fMetazoneItem(NULL),
+ fZoneItem(NULL),
+ fIsFullyLoaded(FALSE)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fTzidToStrings = uhash_open(uhash_hashUChars, // key hash function
+ uhash_compareUChars, // key comparison function
+ NULL, // Value comparison function
+ &status);
+ fMzidToStrings = uhash_open(uhash_hashUChars, // key hash function
+ uhash_compareUChars, // key comparison function
+ NULL, // Value comparison function
+ &status);
+ uhash_setValueDeleter(fTzidToStrings, deleteZoneStrings);
+ uhash_setValueDeleter(fMzidToStrings, deleteZoneStrings);
+}
+
+// Load only a single zone
+void
+ZoneStringFormat::loadZone(const UnicodeString &utzid, UErrorCode &status)
+{
+ if (fIsFullyLoaded) {
+ return;
+ }
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ umtx_lock(&ZoneStringFormatMutex);
+
+ if (fZoneStringsArray == NULL) {
+ fZoneStringsArray = ures_open(U_ICUDATA_ZONE, fLocale.getName(), &status);
+ fZoneStringsArray = ures_getByKeyWithFallback(fZoneStringsArray, gZoneStringsTag, fZoneStringsArray, &status);
+ if (U_FAILURE(status)) {
+ // If no locale bundles are available, zoneStrings will be null.
+ // We still want to go through the rest of zone strings initialization,
+ // because generic location format is generated from tzid for the case.
+ // The rest of code should work even zoneStrings is null.
+ status = U_ZERO_ERROR;
+ ures_close(fZoneStringsArray);
+ fZoneStringsArray = NULL;
+ }
+ }
+
+ // Skip non-canonical IDs
+ UnicodeString canonicalID;
+ TimeZone::getCanonicalID(utzid, canonicalID, status);
+ if (U_FAILURE(status)) {
+ // Ignore unknown ID - we should not get here, but just in case.
+ // status = U_ZERO_ERROR;
+ umtx_unlock(&ZoneStringFormatMutex);
+ return;
+ }
+
+ if (U_SUCCESS(status)) {
+ if (uhash_count(fTzidToStrings) > 0) {
+ ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
+ if (zstrings != NULL) {
+ umtx_unlock(&ZoneStringFormatMutex);
+ return; // We already about this one
+ }
+ }
+ }
+
+ addSingleZone(canonicalID, status);
+
+ umtx_unlock(&ZoneStringFormatMutex);
+}
+
+// Load only a single zone
+void
+ZoneStringFormat::addSingleZone(UnicodeString &utzid, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (uhash_count(fTzidToStrings) > 0) {
+ ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, utzid.getTerminatedBuffer());
+ if (zstrings != NULL) {
+ return; // We already about this one
+ }
+ }
+
+ MessageFormat *fallbackFmt = NULL;
+ MessageFormat *regionFmt = NULL;
+
+ fallbackFmt = getFallbackFormat(fLocale, status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ regionFmt = getRegionFormat(fLocale, status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+
+ {
+ char zidkey[ZID_KEY_MAX+1];
+ char tzid[ZID_KEY_MAX+1];
+ utzid.extract(0, utzid.length(), zidkey, ZID_KEY_MAX, US_INV);
+ utzid.extract(0, utzid.length(), tzid, ZID_KEY_MAX, US_INV);
+
+ const UChar *zstrarray[ZSIDX_COUNT];
+ const UChar *mzstrarray[ZSIDX_COUNT];
+ UnicodeString mzPartialLoc[MAX_METAZONES_PER_ZONE][4];
+
+ // Replace '/' with ':'
+ char *pCity = NULL;
+ char *p = zidkey;
+ while (*p) {
+ if (*p == '/') {
+ *p = ':';
+ pCity = p + 1;
+ }
+ p++;
+ }
+
+ if (fZoneStringsArray != NULL) {
+ fZoneItem = ures_getByKeyWithFallback(fZoneStringsArray, zidkey, fZoneItem, &status);
+ if (U_FAILURE(status)) {
+ // If failed to open the zone item, create only location string
+ ures_close(fZoneItem);
+ fZoneItem = NULL;
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ UnicodeString region;
+ getRegion(region);
+
+ zstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(fZoneItem, gLongStandardTag);
+ zstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(fZoneItem, gShortStandardTag);
+ zstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(fZoneItem, gLongDaylightTag);
+ zstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(fZoneItem, gShortDaylightTag);
+ zstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(fZoneItem, gLongGenericTag);
+ zstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(fZoneItem, gShortGenericTag);
+
+ // Compose location format string
+ UnicodeString location;
+ UnicodeString country;
+ UnicodeString city;
+ UnicodeString countryCode;
+ ZoneMeta::getCanonicalCountry(utzid, countryCode);
+ if (!countryCode.isEmpty()) {
+ const UChar* tmpCity = getZoneStringFromBundle(fZoneItem, gExemplarCityTag);
+ if (tmpCity != NULL) {
+ city.setTo(TRUE, tmpCity, -1);
+ } else {
+ city.setTo(UnicodeString(pCity, -1, US_INV));
+ // Replace '_' with ' '
+ for (int32_t i = 0; i < city.length(); i++) {
+ if (city.charAt(i) == (UChar)0x5F /*'_'*/) {
+ city.setCharAt(i, (UChar)0x20 /*' '*/);
+ }
+ }
+ }
+ getLocalizedCountry(countryCode, fLocale, country);
+ UnicodeString singleCountry;
+ ZoneMeta::getSingleCountry(utzid, singleCountry);
+ FieldPosition fpos;
+ if (singleCountry.isEmpty()) {
+ Formattable params [] = {
+ Formattable(city),
+ Formattable(country)
+ };
+ fallbackFmt->format(params, 2, location, fpos, status);
+ } else {
+ // If the zone is only one zone in the country, do not add city
+ Formattable params [] = {
+ Formattable(country)
+ };
+ regionFmt->format(params, 1, location, fpos, status);
+ }
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ zstrarray[ZSIDX_LOCATION] = location.getTerminatedBuffer();
+ } else {
+ if (uprv_strlen(tzid) > 4 && uprv_strncmp(tzid, "Etc/", 4) == 0) {
+ // "Etc/xxx" is not associated with a specific location, so localized
+ // GMT format is always used as generic location format.
+ zstrarray[ZSIDX_LOCATION] = NULL;
+ } else {
+ // When a new time zone ID, which is actually associated with a specific
+ // location, is added in tzdata, but the current CLDR data does not have
+ // the information yet, ICU creates a generic location string based on
+ // the ID. This implementation supports canonical time zone round trip
+ // with format pattern "VVVV". See #6602 for the details.
+ UnicodeString loc(utzid);
+ int32_t slashIdx = loc.lastIndexOf((UChar)0x2f);
+ if (slashIdx == -1) {
+ // A time zone ID without slash in the tz database is not
+ // associated with a specific location. For instances,
+ // MET, CET, EET and WET fall into this category.
+ // In this case, we still use GMT format as fallback.
+ zstrarray[ZSIDX_LOCATION] = NULL;
+ } else {
+ FieldPosition fpos;
+ Formattable params[] = {
+ Formattable(loc)
+ };
+ regionFmt->format(params, 1, location, fpos, status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ zstrarray[ZSIDX_LOCATION] = location.getTerminatedBuffer();
+ }
+ }
+ }
+
+ UBool commonlyUsed = isCommonlyUsed(fZoneItem);
+
+ // Resolve metazones used by this zone
+ int32_t mzPartialLocIdx = 0;
+ const UVector *metazoneMappings = ZoneMeta::getMetazoneMappings(utzid);
+ if (metazoneMappings != NULL) {
+ for (int32_t i = 0; i < metazoneMappings->size(); i++) {
+ const OlsonToMetaMappingEntry *mzmap =
+ (const OlsonToMetaMappingEntry*)metazoneMappings->elementAt(i);
+ UnicodeString mzid(mzmap->mzid);
+ const ZoneStrings *mzStrings =
+ (const ZoneStrings*)uhash_get(fMzidToStrings, mzid.getTerminatedBuffer());
+ if (mzStrings == NULL) {
+ // If the metazone strings are not yet processed, do it now.
+ char mzidkey[ZID_KEY_MAX];
+ uprv_strcpy(mzidkey, gMetazoneIdPrefix);
+ u_UCharsToChars(mzmap->mzid, mzidkey + MZID_PREFIX_LEN, u_strlen(mzmap->mzid) + 1);
+ fMetazoneItem = ures_getByKeyWithFallback(fZoneStringsArray, mzidkey, fMetazoneItem, &status);
+ if (U_FAILURE(status)) {
+ // No resources available for this metazone
+ // Resource bundle will be cleaned up after end of the loop.
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ UBool mzCommonlyUsed = isCommonlyUsed(fMetazoneItem);
+ mzstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(fMetazoneItem, gLongStandardTag);
+ mzstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(fMetazoneItem, gShortStandardTag);
+ mzstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(fMetazoneItem, gLongDaylightTag);
+ mzstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(fMetazoneItem, gShortDaylightTag);
+ mzstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(fMetazoneItem, gLongGenericTag);
+ mzstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(fMetazoneItem, gShortGenericTag);
+ mzstrarray[ZSIDX_LOCATION] = NULL;
+
+ int32_t lastNonNullIdx = ZSIDX_COUNT - 1;
+ while (lastNonNullIdx >= 0) {
+ if (mzstrarray[lastNonNullIdx] != NULL) {
+ break;
+ }
+ lastNonNullIdx--;
+ }
+ UnicodeString *strings_mz = NULL;
+ ZoneStrings *tmp_mzStrings = NULL;
+ if (lastNonNullIdx >= 0) {
+ // Create UnicodeString array and put strings to the zone string trie
+ strings_mz = new UnicodeString[lastNonNullIdx + 1];
+
+ UnicodeString preferredIdForLocale;
+ ZoneMeta::getZoneIdByMetazone(mzid, region, preferredIdForLocale);
+
+ for (int32_t typeidx = 0; typeidx <= lastNonNullIdx; typeidx++) {
+ if (mzstrarray[typeidx] != NULL) {
+ strings_mz[typeidx].setTo(TRUE, mzstrarray[typeidx], -1);
+
+ // Add a metazone string to the zone string trie
+ int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)typeidx);
+ ZoneStringInfo *zsinfo = new ZoneStringInfo(
+ preferredIdForLocale,
+ strings_mz[typeidx],
+ (TimeZoneTranslationType)type,
+ fStringPool,
+ status);
+ fZoneStringsTrie.put(strings_mz[typeidx], zsinfo, fStringPool, status);
+ if (U_FAILURE(status)) {
+ delete []strings_mz;
+ goto error_cleanup;
+ }
+ }
+ }
+ // Note: ZoneStrings constructor adopts and deletes the strings_mz array.
+ tmp_mzStrings = new ZoneStrings(strings_mz, lastNonNullIdx + 1,
+ mzCommonlyUsed, NULL, 0, 0, fStringPool, status);
+ } else {
+ // Create ZoneStrings with empty contents
+ tmp_mzStrings = new ZoneStrings(NULL, 0, FALSE, NULL, 0, 0, fStringPool, status);
+ }
+
+ UChar *umzid = const_cast<UChar *>(fStringPool.get(mzid, status));
+ uhash_put(fMzidToStrings, umzid, tmp_mzStrings, &status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ mzStrings = tmp_mzStrings;
+ }
+
+ // Compose generic partial location format
+ UnicodeString lg;
+ UnicodeString sg;
+
+ mzStrings->getString(ZSIDX_LONG_GENERIC, lg);
+ mzStrings->getString(ZSIDX_SHORT_GENERIC, sg);
+
+ if (!lg.isEmpty() || !sg.isEmpty()) {
+ UBool addMzPartialLocationNames = TRUE;
+ for (int32_t j = 0; j < mzPartialLocIdx; j++) {
+ if (mzPartialLoc[j][0] == mzid) {
+ // already processed
+ addMzPartialLocationNames = FALSE;
+ break;
+ }
+ }
+ if (addMzPartialLocationNames) {
+ UnicodeString *locationPart = NULL;
+ // Check if the zone is the preferred zone for the territory associated with the zone
+ UnicodeString preferredID;
+ ZoneMeta::getZoneIdByMetazone(mzid, countryCode, preferredID);
+ if (utzid == preferredID) {
+ // Use country for the location
+ locationPart = &country;
+ } else {
+ // Use city for the location
+ locationPart = &city;
+ }
+ // Reset the partial location string array
+ mzPartialLoc[mzPartialLocIdx][0].setTo(mzid);
+ mzPartialLoc[mzPartialLocIdx][1].remove();
+ mzPartialLoc[mzPartialLocIdx][2].remove();
+ mzPartialLoc[mzPartialLocIdx][3].remove();
+
+ if (locationPart->length() != 0) {
+ FieldPosition fpos;
+ if (!lg.isEmpty()) {
+ Formattable params [] = {
+ Formattable(*locationPart),
+ Formattable(lg)
+ };
+ fallbackFmt->format(params, 2, mzPartialLoc[mzPartialLocIdx][1], fpos, status);
+ }
+ if (!sg.isEmpty()) {
+ Formattable params [] = {
+ Formattable(*locationPart),
+ Formattable(sg)
+ };
+ fallbackFmt->format(params, 2, mzPartialLoc[mzPartialLocIdx][2], fpos, status);
+ if (mzStrings->isShortFormatCommonlyUsed()) {
+ mzPartialLoc[mzPartialLocIdx][3].setTo(TRUE, gCommonlyUsedTrue, -1);
+ }
+ }
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ }
+ mzPartialLocIdx++;
+ }
+ }
+ }
+ }
+ // Collected names for a zone
+
+ // Create UnicodeString array for localized zone strings
+ int32_t lastIdx = ZSIDX_COUNT - 1;
+ while (lastIdx >= 0) {
+ if (zstrarray[lastIdx] != NULL) {
+ break;
+ }
+ lastIdx--;
+ }
+ UnicodeString *strings = NULL;
+ int32_t stringsCount = lastIdx + 1;
+
+ if (stringsCount > 0) {
+ strings = new UnicodeString[stringsCount];
+ for (int32_t i = 0; i < stringsCount; i++) {
+ if (zstrarray[i] != NULL) {
+ strings[i].setTo(zstrarray[i], -1);
+
+ // Add names to the trie
+ int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)i);
+ ZoneStringInfo *zsinfo = new ZoneStringInfo(utzid,
+ strings[i],
+ (TimeZoneTranslationType)type,
+ fStringPool,
+ status);
+ fZoneStringsTrie.put(strings[i], zsinfo, fStringPool, status);
+ if (U_FAILURE(status)) {
+ delete zsinfo;
+ delete[] strings;
+ goto error_cleanup;
+ }
+ }
+ }
+ }
+
+ // Create UnicodeString array for generic partial location strings
+ UnicodeString **genericPartialLocationNames = NULL;
+ int32_t genericPartialRowCount = mzPartialLocIdx;
+ int32_t genericPartialColCount = 4;
+
+ if (genericPartialRowCount != 0) {
+ genericPartialLocationNames =
+ (UnicodeString**)uprv_malloc(genericPartialRowCount * sizeof(UnicodeString*));
+ if (genericPartialLocationNames == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete[] strings;
+ goto error_cleanup;
+ }
+ for (int32_t i = 0; i < genericPartialRowCount; i++) {
+ genericPartialLocationNames[i] = new UnicodeString[genericPartialColCount];
+ for (int32_t j = 0; j < genericPartialColCount; j++) {
+ genericPartialLocationNames[i][j].setTo(mzPartialLoc[i][j]);
+ // Add names to the trie
+ if ((j == 1 || j == 2) &&!genericPartialLocationNames[i][j].isEmpty()) {
+ ZoneStringInfo *zsinfo;
+ TimeZoneTranslationType type = (j == 1) ? GENERIC_LONG : GENERIC_SHORT;
+ zsinfo = new ZoneStringInfo(utzid, genericPartialLocationNames[i][j], type,
+ fStringPool, status);
+ fZoneStringsTrie.put(genericPartialLocationNames[i][j], zsinfo, fStringPool, status);
+ if (U_FAILURE(status)) {
+ delete[] genericPartialLocationNames[i];
+ uprv_free(genericPartialLocationNames);
+ delete[] strings;
+ goto error_cleanup;
+ }
+ }
+ }
+ }
+ }
+
+ // Finally, create ZoneStrings instance and put it into the tzidToStinrgs map
+ ZoneStrings *zstrings = new ZoneStrings(strings, stringsCount, commonlyUsed,
+ genericPartialLocationNames, genericPartialRowCount,
+ genericPartialColCount, fStringPool, status);
+
+ UChar *uutzid = const_cast<UChar *>(fStringPool.get(utzid, status));
+ uhash_put(fTzidToStrings, uutzid, zstrings, &status);
+ if (U_FAILURE(status)) {
+ delete zstrings;
+ goto error_cleanup;
+ }
+ }
+
+error_cleanup:
+ if (fallbackFmt != NULL) {
+ delete fallbackFmt;
+ }
+ if (regionFmt != NULL) {
+ delete regionFmt;
+ }
+ // fStringPool.freeze();
+}
+
+void
+ZoneStringFormat::loadFull(UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fIsFullyLoaded) {
+ return;
+ }
+
+ umtx_lock(&ZoneStringFormatMutex);
+
+ if (fZoneStringsArray == NULL) {
+ fZoneStringsArray = ures_open(U_ICUDATA_ZONE, fLocale.getName(), &status);
+ fZoneStringsArray = ures_getByKeyWithFallback(fZoneStringsArray, gZoneStringsTag, fZoneStringsArray, &status);
+ if (U_FAILURE(status)) {
+ // If no locale bundles are available, zoneStrings will be null.
+ // We still want to go through the rest of zone strings initialization,
+ // because generic location format is generated from tzid for the case.
+ // The rest of code should work even zoneStrings is null.
+ status = U_ZERO_ERROR;
+ ures_close(fZoneStringsArray);
+ fZoneStringsArray = NULL;
+ }
+ }
+
+ StringEnumeration *tzids = NULL;
+
+ tzids = TimeZone::createEnumeration();
+ const char *tzid;
+ while ((tzid = tzids->next(NULL, status))) {
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ // Skip non-canonical IDs
+ UnicodeString utzid(tzid, -1, US_INV);
+ UnicodeString canonicalID;
+ TimeZone::getCanonicalID(utzid, canonicalID, status);
+ if (U_FAILURE(status)) {
+ // Ignore unknown ID - we should not get here, but just in case.
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ if (U_SUCCESS(status)) {
+ if (uhash_count(fTzidToStrings) > 0) {
+ ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
+ if (zstrings != NULL) {
+ continue; // We already about this one
+ }
+ }
+ }
+
+ addSingleZone(canonicalID, status);
+
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ }
+
+ fIsFullyLoaded = TRUE;
+
+error_cleanup:
+ if (tzids != NULL) {
+ delete tzids;
+ }
+ fStringPool.freeze();
+
+ umtx_unlock(&ZoneStringFormatMutex);
+}
+
+
+ZoneStringFormat::~ZoneStringFormat() {
+ uhash_close(fTzidToStrings);
+ uhash_close(fMzidToStrings);
+ ures_close(fZoneItem);
+ ures_close(fMetazoneItem);
+ ures_close(fZoneStringsArray);
+}
+
+SafeZoneStringFormatPtr*
+ZoneStringFormat::getZoneStringFormat(const Locale& locale, UErrorCode &status) {
+ umtx_lock(&gZSFCacheLock);
+ if (gZoneStringFormatCache == NULL) {
+ gZoneStringFormatCache = new ZSFCache(10 /* capacity */);
+ ucln_i18n_registerCleanup(UCLN_I18N_ZSFORMAT, zoneStringFormat_cleanup);
+ }
+ umtx_unlock(&gZSFCacheLock);
+
+ return gZoneStringFormatCache->get(locale, status);
+}
+
+
+UnicodeString**
+ZoneStringFormat::createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ ZoneStringFormat *nonConstThis = const_cast<ZoneStringFormat *>(this);
+ nonConstThis->loadFull(status);
+
+ UnicodeString **result = NULL;
+ rowCount = 0;
+ colCount = 0;
+
+ // Collect canonical time zone IDs
+ UVector canonicalIDs(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ StringEnumeration *tzids = TimeZone::createEnumeration();
+ const UChar *tzid;
+ while ((tzid = tzids->unext(NULL, status))) {
+ if (U_FAILURE(status)) {
+ delete tzids;
+ return NULL;
+ }
+ UnicodeString utzid(tzid);
+ UnicodeString canonicalID;
+ TimeZone::getCanonicalID(UnicodeString(tzid), canonicalID, status);
+ if (U_FAILURE(status)) {
+ // Ignore unknown ID - we should not get here, but just in case.
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ if (utzid == canonicalID) {
+ canonicalIDs.addElement(new UnicodeString(utzid), status);
+ if (U_FAILURE(status)) {
+ delete tzids;
+ return NULL;
+ }
+ }
+ }
+ delete tzids;
+
+ // Allocate array
+ result = (UnicodeString**)uprv_malloc(canonicalIDs.size() * sizeof(UnicodeString*));
+ if (result == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ for (int32_t i = 0; i < canonicalIDs.size(); i++) {
+ result[i] = new UnicodeString[8];
+ UnicodeString *id = (UnicodeString*)canonicalIDs.elementAt(i);
+ result[i][0].setTo(*id);
+ getLongStandard(*id, date, result[i][1]);
+ getShortStandard(*id, date, FALSE, result[i][2]);
+ getLongDaylight(*id, date, result[i][3]);
+ getShortDaylight(*id, date, FALSE, result[i][4]);
+ getGenericLocation(*id, result[i][5]);
+ getLongGenericNonLocation(*id, date, result[i][6]);
+ getShortGenericNonLocation(*id, date, FALSE, result[i][7]);
+ }
+
+ rowCount = canonicalIDs.size();
+ colCount = 8;
+ return result;
+}
+
+UnicodeString&
+ZoneStringFormat::getSpecificLongString(const Calendar &cal, UnicodeString &result,
+ UErrorCode &status) const {
+ result.remove();
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ UnicodeString tzid;
+ cal.getTimeZone().getID(tzid);
+ UDate date = cal.getTime(status);
+ if (cal.get(UCAL_DST_OFFSET, status) == 0) {
+ return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /*not used*/, result);
+ } else {
+ return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /*not used*/, result);
+ }
+}
+
+UnicodeString&
+ZoneStringFormat::getSpecificShortString(const Calendar &cal, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const {
+ result.remove();
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ UnicodeString tzid;
+ cal.getTimeZone().getID(tzid);
+ UDate date = cal.getTime(status);
+ if (cal.get(UCAL_DST_OFFSET, status) == 0) {
+ return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
+ } else {
+ return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
+ }
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericLongString(const Calendar &cal, UnicodeString &result,
+ UErrorCode &status) const {
+ return getGenericString(cal, FALSE /*long*/, FALSE /* not used */, result, status);
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericShortString(const Calendar &cal, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const {
+ return getGenericString(cal, TRUE /*short*/, commonlyUsedOnly, result, status);
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericLocationString(const Calendar &cal, UnicodeString &result,
+ UErrorCode &status) const {
+ UnicodeString tzid;
+ cal.getTimeZone().getID(tzid);
+ UDate date = cal.getTime(status);
+ return getString(tzid, ZSIDX_LOCATION, date, FALSE /*not used*/, result);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findSpecificLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, STANDARD_LONG | DAYLIGHT_LONG, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findSpecificShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, STANDARD_SHORT | DAYLIGHT_SHORT, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findGenericLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, GENERIC_LONG | STANDARD_LONG | LOCATION, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findGenericShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, GENERIC_SHORT | STANDARD_SHORT | LOCATION, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findGenericLocation(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, LOCATION, matchLength, status);
+}
+
+UnicodeString&
+ZoneStringFormat::getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
+ UBool commonlyUsedOnly, UnicodeString& result) const {
+ UErrorCode status = U_ZERO_ERROR;
+ result.remove();
+ if (!fIsFullyLoaded) {
+ // Lazy loading
+ ZoneStringFormat *nonConstThis = const_cast<ZoneStringFormat *>(this);
+ nonConstThis->loadZone(tzid, status);
+ }
+
+ // ICU's own array does not have entries for aliases
+ UnicodeString canonicalID;
+ TimeZone::getCanonicalID(tzid, canonicalID, status);
+ if (U_FAILURE(status)) {
+ // Unknown ID, but users might have their own data.
+ canonicalID.setTo(tzid);
+ }
+
+ if (uhash_count(fTzidToStrings) > 0) {
+ ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
+ if (zstrings != NULL) {
+ switch (typeIdx) {
+ case ZSIDX_LONG_STANDARD:
+ case ZSIDX_LONG_DAYLIGHT:
+ case ZSIDX_LONG_GENERIC:
+ case ZSIDX_LOCATION:
+ zstrings->getString(typeIdx, result);
+ break;
+ case ZSIDX_SHORT_STANDARD:
+ case ZSIDX_SHORT_DAYLIGHT:
+ case ZSIDX_COUNT: //added to avoid warning
+ case ZSIDX_SHORT_GENERIC:
+ if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) {
+ zstrings->getString(typeIdx, result);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (result.isEmpty() && uhash_count(fMzidToStrings) > 0 && typeIdx != ZSIDX_LOCATION) {
+ // Try metazone
+ UnicodeString mzid;
+ ZoneMeta::getMetazoneID(canonicalID, date, mzid);
+ if (!mzid.isEmpty()) {
+ ZoneStrings *mzstrings = (ZoneStrings*)uhash_get(fMzidToStrings, mzid.getTerminatedBuffer());
+ if (mzstrings != NULL) {
+ switch (typeIdx) {
+ case ZSIDX_LONG_STANDARD:
+ case ZSIDX_LONG_DAYLIGHT:
+ case ZSIDX_LONG_GENERIC:
+ case ZSIDX_LOCATION:
+ mzstrings->getString(typeIdx, result);
+ break;
+ case ZSIDX_SHORT_STANDARD:
+ case ZSIDX_SHORT_DAYLIGHT:
+ case ZSIDX_COUNT: //added to avoid warning
+ case ZSIDX_SHORT_GENERIC:
+ if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) {
+ mzstrings->getString(typeIdx, result);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const {
+ result.remove();
+ UDate time = cal.getTime(status);
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ const TimeZone &tz = cal.getTimeZone();
+ UnicodeString tzid;
+ tz.getID(tzid);
+
+ if (!fIsFullyLoaded) {
+ // Lazy loading
+ ZoneStringFormat *nonConstThis = const_cast<ZoneStringFormat *>(this);
+ nonConstThis->loadZone(tzid, status);
+ }
+
+ // ICU's own array does not have entries for aliases
+ UnicodeString canonicalID;
+ TimeZone::getCanonicalID(tzid, canonicalID, status);
+ if (U_FAILURE(status)) {
+ // Unknown ID, but users might have their own data.
+ status = U_ZERO_ERROR;
+ canonicalID.setTo(tzid);
+ }
+
+ ZoneStrings *zstrings = NULL;
+ if (uhash_count(fTzidToStrings) > 0) {
+ zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
+ if (zstrings != NULL) {
+ if (isShort) {
+ if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) {
+ zstrings->getString(ZSIDX_SHORT_GENERIC, result);
+ }
+ } else {
+ zstrings->getString(ZSIDX_LONG_GENERIC, result);
+ }
+ }
+ }
+ if (result.isEmpty() && uhash_count(fMzidToStrings) > 0) {
+ // try metazone
+ int32_t raw, sav;
+ UnicodeString mzid;
+ ZoneMeta::getMetazoneID(canonicalID, time, mzid);
+ if (!mzid.isEmpty()) {
+ UBool useStandard = FALSE;
+ sav = cal.get(UCAL_DST_OFFSET, status);
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ if (sav == 0) {
+ useStandard = TRUE;
+ // Check if the zone actually uses daylight saving time around the time
+ TimeZone *tmptz = tz.clone();
+ BasicTimeZone *btz = NULL;
+ if (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(time, TRUE, before);
+ if (beforTrs
+ && (time - before.getTime() < kDstCheckRange)
+ && before.getFrom()->getDSTSavings() != 0) {
+ useStandard = FALSE;
+ } else {
+ TimeZoneTransition after;
+ UBool afterTrs = btz->getNextTransition(time, FALSE, after);
+ if (afterTrs
+ && (after.getTime() - time < kDstCheckRange)
+ && after.getTo()->getDSTSavings() != 0) {
+ useStandard = FALSE;
+ }
+ }
+ } else {
+ // If not BasicTimeZone... only if the instance is not an ICU's implementation.
+ // We may get a wrong answer in edge case, but it should practically work OK.
+ tmptz->getOffset(time - kDstCheckRange, FALSE, raw, sav, status);
+ if (sav != 0) {
+ useStandard = FALSE;
+ } else {
+ tmptz->getOffset(time + kDstCheckRange, FALSE, raw, sav, status);
+ if (sav != 0){
+ useStandard = FALSE;
+ }
+ }
+ if (U_FAILURE(status)) {
+ delete tmptz;
+ result.remove();
+ return result;
+ }
+ }
+ delete tmptz;
+ }
+ if (useStandard) {
+ getString(canonicalID, (isShort ? ZSIDX_SHORT_STANDARD : ZSIDX_LONG_STANDARD),
+ time, commonlyUsedOnly, result);
+
+ // Note:
+ // In CLDR 1.5.1, a same localization is used for both generic and standard
+ // for some metazones in some locales. This is actually data bugs and should
+ // be resolved in later versions of CLDR. For now, we check if the standard
+ // name is different from its generic name below.
+ if (!result.isEmpty()) {
+ UnicodeString genericNonLocation;
+ getString(canonicalID, (isShort ? ZSIDX_SHORT_GENERIC : ZSIDX_LONG_GENERIC),
+ time, commonlyUsedOnly, genericNonLocation);
+ if (!genericNonLocation.isEmpty() && result == genericNonLocation) {
+ result.remove();
+ }
+ }
+ }
+ if (result.isEmpty()) {
+ ZoneStrings *mzstrings = (ZoneStrings*)uhash_get(fMzidToStrings, mzid.getTerminatedBuffer());
+ if (mzstrings != NULL) {
+ if (isShort) {
+ if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) {
+ mzstrings->getString(ZSIDX_SHORT_GENERIC, result);
+ }
+ } else {
+ mzstrings->getString(ZSIDX_LONG_GENERIC, result);
+ }
+ }
+ if (!result.isEmpty()) {
+ // Check if the offsets at the given time matches the preferred zone's offsets
+ UnicodeString preferredId;
+ UnicodeString region;
+ ZoneMeta::getZoneIdByMetazone(mzid, getRegion(region), preferredId);
+ if (canonicalID != preferredId) {
+ // Check if the offsets at the given time are identical with the preferred zone
+ raw = cal.get(UCAL_ZONE_OFFSET, status);
+ if (U_FAILURE(status)) {
+ result.remove();
+ return result;
+ }
+ TimeZone *preferredZone = TimeZone::createTimeZone(preferredId);
+ int32_t prfRaw, prfSav;
+ // Check offset in preferred time zone with wall time.
+ // With getOffset(time, false, preferredOffsets),
+ // you may get incorrect results because of time overlap at DST->STD
+ // transition.
+ preferredZone->getOffset(time + raw + sav, TRUE, prfRaw, prfSav, status);
+ delete preferredZone;
+
+ if (U_FAILURE(status)) {
+ result.remove();
+ return result;
+ }
+ if ((raw != prfRaw || sav != prfSav) && zstrings != NULL) {
+ // Use generic partial location string as fallback
+ zstrings->getGenericPartialLocationString(mzid, isShort, commonlyUsedOnly, result);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (result.isEmpty()) {
+ // Use location format as the final fallback
+ getString(canonicalID, ZSIDX_LOCATION, time, FALSE /*not used*/, result);
+ }
+
+ return result;
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
+ UDate date, UBool commonlyUsedOnly, UnicodeString &result) const {
+ UErrorCode status = U_ZERO_ERROR;
+ result.remove();
+ if (!fIsFullyLoaded) {
+ // Lazy loading
+ ZoneStringFormat *nonConstThis = const_cast<ZoneStringFormat *>(this);
+ nonConstThis->loadZone(tzid, status);
+ }
+
+ if (uhash_count(fTzidToStrings) <= 0) {
+ return result;
+ }
+
+ UnicodeString canonicalID;
+ TimeZone::getCanonicalID(tzid, canonicalID, status);
+ if (U_FAILURE(status)) {
+ // Unknown ID, so no corresponding meta data.
+ return result;
+ }
+
+ UnicodeString mzid;
+ ZoneMeta::getMetazoneID(canonicalID, date, mzid);
+
+ if (!mzid.isEmpty()) {
+ ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
+ if (zstrings != NULL) {
+ zstrings->getGenericPartialLocationString(mzid, isShort, commonlyUsedOnly, result);
+ }
+ }
+ return result;
+}
+
+// This method does lazy zone string loading
+const ZoneStringInfo*
+ZoneStringFormat::find(const UnicodeString &text, int32_t start, int32_t types,
+ int32_t &matchLength, UErrorCode &status) const {
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ const ZoneStringInfo * result = subFind(text, start, types, matchLength, status);
+ if (fIsFullyLoaded) {
+ return result;
+ }
+ // When zone string data is partially loaded,
+ // this method return the result only when
+ // the input text is fully consumed.
+ if (result != NULL) {
+ UnicodeString tmpString;
+ matchLength = (result->getString(tmpString)).length();
+ if (text.length() - start == matchLength) {
+ return result;
+ }
+ }
+
+ // Now load all zone strings
+ ZoneStringFormat *nonConstThis = const_cast<ZoneStringFormat *>(this);
+ nonConstThis->loadFull(status);
+
+ return subFind(text, start, types, matchLength, status);
+}
+
+
+/*
+ * Find a prefix matching time zone for the given zone string types.
+ * @param text The text contains a time zone string
+ * @param start The start index within the text
+ * @param types The bit mask representing a set of requested types
+ * @return If any zone string matched for the requested types, returns a
+ * ZoneStringInfo for the longest match. If no matches are found for
+ * the requested types, returns a ZoneStringInfo for the longest match
+ * for any other types. If nothing matches at all, returns null.
+ */
+const ZoneStringInfo*
+ZoneStringFormat::subFind(const UnicodeString &text, int32_t start, int32_t types,
+ int32_t &matchLength, UErrorCode &status) const {
+ matchLength = 0;
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (fZoneStringsTrie.isEmpty()) {
+ return NULL;
+ }
+
+ const ZoneStringInfo *result = NULL;
+ const ZoneStringInfo *fallback = NULL;
+ int32_t fallbackMatchLen = 0;
+
+ ZoneStringSearchResultHandler handler(status);
+ fZoneStringsTrie.search(text, start, (TextTrieMapSearchResultHandler*)&handler, status);
+ if (U_SUCCESS(status)) {
+ int32_t numMatches = handler.countMatches();
+ for (int32_t i = 0; i < numMatches; i++) {
+ int32_t tmpMatchLen = 0; // init. output only param to silence gcc
+ const ZoneStringInfo *tmp = handler.getMatch(i, tmpMatchLen);
+ if ((types & tmp->fType) != 0) {
+ if (result == NULL || matchLength < tmpMatchLen) {
+ result = tmp;
+ matchLength = tmpMatchLen;
+ } else if (matchLength == tmpMatchLen) {
+ // Tie breaker - there are some examples that a
+ // long standard name is identical with a location
+ // name - for example, "Uruguay Time". In this case,
+ // we interpret it as generic, not specific.
+ if (tmp->isGeneric() && !result->isGeneric()) {
+ result = tmp;
+ }
+ }
+ } else if (result == NULL) {
+ if (fallback == NULL || fallbackMatchLen < tmpMatchLen) {
+ fallback = tmp;
+ fallbackMatchLen = tmpMatchLen;
+ } else if (fallbackMatchLen == tmpMatchLen) {
+ if (tmp->isGeneric() && !fallback->isGeneric()) {
+ fallback = tmp;
+ }
+ }
+ }
+ }
+ if (result == NULL && fallback != NULL) {
+ result = fallback;
+ matchLength = fallbackMatchLen;
+ }
+ }
+ return result;
+}
+
+
+UnicodeString&
+ZoneStringFormat::getRegion(UnicodeString &region) const {
+ const char* country = fLocale.getCountry();
+ // TODO: Utilize addLikelySubtag in Locale to resolve default region
+ // when the implementation is ready.
+ region.setTo(UnicodeString(country, -1, US_INV));
+ return region;
+}
+
+MessageFormat*
+ZoneStringFormat::getFallbackFormat(const Locale &locale, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString pattern(TRUE, gDefFallbackPattern, -1);
+ UResourceBundle *zoneStringsArray = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
+ zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
+ int32_t len;
+ const UChar *flbkfmt = ures_getStringByKeyWithFallback(zoneStringsArray, gFallbackFormatTag, &len, &status);
+ if (U_SUCCESS(status)) {
+ pattern.setTo(flbkfmt);
+ } else {
+ status = U_ZERO_ERROR;
+ }
+ ures_close(zoneStringsArray);
+
+ MessageFormat *fallbackFmt = new MessageFormat(pattern, status);
+ return fallbackFmt;
+}
+
+MessageFormat*
+ZoneStringFormat::getRegionFormat(const Locale& locale, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString pattern(TRUE, gDefRegionPattern, -1);
+ UResourceBundle *zoneStringsArray = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
+ zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
+ int32_t len;
+ const UChar *regionfmt = ures_getStringByKeyWithFallback(zoneStringsArray, gRegionFormatTag, &len, &status);
+ if (U_SUCCESS(status)) {
+ pattern.setTo(regionfmt);
+ } else {
+ status = U_ZERO_ERROR;
+ }
+ ures_close(zoneStringsArray);
+
+ MessageFormat *regionFmt = new MessageFormat(pattern, status);
+ return regionFmt;
+}
+
+const UChar*
+ZoneStringFormat::getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key) {
+ const UChar *str = NULL;
+ if (zoneitem != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len;
+ str = ures_getStringByKeyWithFallback(zoneitem, key, &len, &status);
+ str = fStringPool.adopt(str, status);
+ if (U_FAILURE(status)) {
+ str = NULL;
+ }
+ }
+ return str;
+}
+
+UBool
+ZoneStringFormat::isCommonlyUsed(const UResourceBundle *zoneitem) {
+ if (zoneitem == NULL) {
+ return TRUE;
+ }
+
+ UBool commonlyUsed = FALSE;
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *cuRes = ures_getByKey(zoneitem, gCommonlyUsedTag, NULL, &status);
+ int32_t cuValue = ures_getInt(cuRes, &status);
+ if (U_SUCCESS(status)) {
+ if (cuValue == 1) {
+ commonlyUsed = TRUE;
+ }
+ }
+ ures_close(cuRes);
+ return commonlyUsed;
+}
+
+UnicodeString&
+ZoneStringFormat::getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale, UnicodeString &displayCountry) {
+ // We do not want to use display country names only from the target language bundle
+ // Note: we should do this in better way.
+ displayCountry.remove();
+ int32_t ccLen = countryCode.length();
+ if (ccLen > 0 && ccLen < ULOC_COUNTRY_CAPACITY) {
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
+ if (U_SUCCESS(status)) {
+ const char *bundleLocStr = ures_getLocale(localeBundle, &status);
+ if (U_SUCCESS(status) && uprv_strlen(bundleLocStr) > 0) {
+ Locale bundleLoc(bundleLocStr);
+ if (uprv_strcmp(bundleLocStr, "root") != 0 &&
+ uprv_strcmp(bundleLoc.getLanguage(), locale.getLanguage()) == 0) {
+ // Create a fake locale strings
+ char tmpLocStr[ULOC_COUNTRY_CAPACITY + 3];
+ uprv_strcpy(tmpLocStr, "xx_");
+ u_UCharsToChars(countryCode.getBuffer(), &tmpLocStr[3], ccLen);
+ tmpLocStr[3 + ccLen] = 0;
+
+ Locale tmpLoc(tmpLocStr);
+ tmpLoc.getDisplayCountry(locale, displayCountry);
+ }
+ }
+ }
+ ures_close(localeBundle);
+ }
+ if (displayCountry.isEmpty()) {
+ // Use the country code as the fallback
+ displayCountry.setTo(countryCode);
+ }
+ return displayCountry;
+}
+
+// ----------------------------------------------------------------------------
+/*
+ * ZoneStrings constructor adopts (and promptly copies and deletes)
+ * the input UnicodeString arrays.
+ */
+ZoneStrings::ZoneStrings(UnicodeString *strings,
+ int32_t stringsCount,
+ UBool commonlyUsed,
+ UnicodeString **genericPartialLocationStrings,
+ int32_t genericRowCount,
+ int32_t genericColCount,
+ ZSFStringPool &sp,
+ UErrorCode &status)
+: fStrings(NULL),
+ fStringsCount(stringsCount),
+ fIsCommonlyUsed(commonlyUsed),
+ fGenericPartialLocationStrings(NULL),
+ fGenericPartialLocationRowCount(genericRowCount),
+ fGenericPartialLocationColCount(genericColCount)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int32_t i, j;
+ if (strings != NULL) {
+ fStrings = (const UChar **)uprv_malloc(sizeof(const UChar **) * stringsCount);
+ if (fStrings == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (i=0; i<fStringsCount; i++) {
+ fStrings[i] = sp.get(strings[i], status);
+ }
+ delete[] strings;
+ }
+ if (genericPartialLocationStrings != NULL) {
+ fGenericPartialLocationStrings =
+ (const UChar ***)uprv_malloc(sizeof(const UChar ***) * genericRowCount);
+ if (fGenericPartialLocationStrings == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (i=0; i < fGenericPartialLocationRowCount; i++) {
+ fGenericPartialLocationStrings[i] =
+ (const UChar **)uprv_malloc(sizeof(const UChar **) * genericColCount);
+ if (fGenericPartialLocationStrings[i] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ continue; // Continue so that fGenericPartialLocationStrings will not contain uninitialized junk,
+ } // which would crash the destructor.
+ for (j=0; j<genericColCount; j++) {
+ fGenericPartialLocationStrings[i][j] =
+ sp.get(genericPartialLocationStrings[i][j], status);
+ }
+ delete[] genericPartialLocationStrings[i];
+ }
+ uprv_free(genericPartialLocationStrings);
+ }
+}
+
+ZoneStrings::~ZoneStrings() {
+ uprv_free(fStrings);
+ if (fGenericPartialLocationStrings != NULL) {
+ for (int32_t i = 0; i < fGenericPartialLocationRowCount; i++) {
+ uprv_free(fGenericPartialLocationStrings[i]);
+ }
+ uprv_free(fGenericPartialLocationStrings);
+ }
+}
+
+
+UnicodeString&
+ZoneStrings::getString(int32_t typeIdx, UnicodeString &result) const {
+ if (typeIdx >= 0 && typeIdx < fStringsCount) {
+ result.setTo(fStrings[typeIdx], -1);
+ } else {
+ result.remove();
+ }
+ return result;
+}
+
+UnicodeString&
+ZoneStrings::getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
+ UBool commonlyUsedOnly, UnicodeString &result) const {
+ UBool isSet = FALSE;
+ if (fGenericPartialLocationColCount >= 2) {
+ for (int32_t i = 0; i < fGenericPartialLocationRowCount; i++) {
+ if (mzid.compare(fGenericPartialLocationStrings[i][0], -1) == 0) {
+ if (isShort) {
+ if (fGenericPartialLocationColCount >= 3) {
+ if (!commonlyUsedOnly ||
+ fGenericPartialLocationColCount == 3 ||
+ fGenericPartialLocationStrings[i][3][0] != 0) {
+ result.setTo(fGenericPartialLocationStrings[i][2], -1);
+ isSet = TRUE;
+ }
+ }
+ } else {
+ result.setTo(fGenericPartialLocationStrings[i][1], -1);
+ isSet = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ if (!isSet) {
+ result.remove();
+ }
+ return result;
+}
+
+// --------------------------------------------------------------
+SafeZoneStringFormatPtr::SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry)
+: fCacheEntry(cacheEntry) {
+}
+
+SafeZoneStringFormatPtr::~SafeZoneStringFormatPtr() {
+ fCacheEntry->delRef();
+}
+
+const ZoneStringFormat*
+SafeZoneStringFormatPtr::get() const {
+ return fCacheEntry->getZoneStringFormat();
+}
+
+ZSFCacheEntry::ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next)
+: fLocale(locale), fZoneStringFormat(zsf),
+ fNext(next), fRefCount(1)
+{
+}
+
+ZSFCacheEntry::~ZSFCacheEntry () {
+ delete fZoneStringFormat;
+}
+
+const ZoneStringFormat*
+ZSFCacheEntry::getZoneStringFormat(void) {
+ return (const ZoneStringFormat*)fZoneStringFormat;
+}
+
+void
+ZSFCacheEntry::delRef(void) {
+ umtx_lock(&gZSFCacheLock);
+ --fRefCount;
+ umtx_unlock(&gZSFCacheLock);
+}
+
+ZSFCache::ZSFCache(int32_t capacity)
+: fCapacity(capacity), fFirst(NULL) {
+}
+
+ZSFCache::~ZSFCache() {
+ ZSFCacheEntry *entry = fFirst;
+ while (entry) {
+ ZSFCacheEntry *next = entry->fNext;
+ delete entry;
+ entry = next;
+ }
+}
+
+SafeZoneStringFormatPtr*
+ZSFCache::get(const Locale &locale, UErrorCode &status) {
+ SafeZoneStringFormatPtr *result = NULL;
+
+ // Search the cache entry list
+ ZSFCacheEntry *entry = NULL;
+ ZSFCacheEntry *next, *prev;
+
+ umtx_lock(&gZSFCacheLock);
+ entry = fFirst;
+ prev = NULL;
+ while (entry) {
+ next = entry->fNext;
+ if (entry->fLocale == locale) {
+ // Add reference count
+ entry->fRefCount++;
+
+ // move the entry to the top
+ if (entry != fFirst) {
+ prev->fNext = next;
+ entry->fNext = fFirst;
+ fFirst = entry;
+ }
+ break;
+ }
+ prev = entry;
+ entry = next;
+ }
+ umtx_unlock(&gZSFCacheLock);
+
+ // Create a new ZoneStringFormat
+ if (entry == NULL) {
+ ZoneStringFormat *zsf = new ZoneStringFormat(locale, status);
+ if (U_FAILURE(status)) {
+ delete zsf;
+ return NULL;
+ }
+ if (zsf == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ // Now add the new entry
+ umtx_lock(&gZSFCacheLock);
+ // Make sure no other threads already created the one for the same locale
+ entry = fFirst;
+ prev = NULL;
+ while (entry) {
+ next = entry->fNext;
+ if (entry->fLocale == locale) {
+ // Add reference count
+ entry->fRefCount++;
+
+ // move the entry to the top
+ if (entry != fFirst) {
+ prev->fNext = next;
+ entry->fNext = fFirst;
+ fFirst = entry;
+ }
+ break;
+ }
+ prev = entry;
+ entry = next;
+ }
+ if (entry == NULL) {
+ // Add the new one to the top
+ next = fFirst;
+ entry = new ZSFCacheEntry(locale, zsf, next);
+ fFirst = entry;
+ } else {
+ delete zsf;
+ }
+ umtx_unlock(&gZSFCacheLock);
+ }
+
+ result = new SafeZoneStringFormatPtr(entry);
+
+ // Now, delete unused cache entries beyond the capacity
+ umtx_lock(&gZSFCacheLock);
+ entry = fFirst;
+ prev = NULL;
+ int32_t idx = 1;
+ while (entry) {
+ next = entry->fNext;
+ if (idx >= fCapacity && entry->fRefCount == 0) {
+ if (entry == fFirst) {
+ fFirst = next;
+ } else {
+ prev->fNext = next;
+ }
+ delete entry;
+ } else {
+ prev = entry;
+ }
+ entry = next;
+ idx++;
+ }
+ umtx_unlock(&gZSFCacheLock);
+
+ return result;
+}
+
+
+/*
+ * Zone String Formatter String Pool Implementation
+ *
+ * String pool for (UChar *) strings. Avoids having repeated copies of the same string.
+ */
+
+static const int32_t POOL_CHUNK_SIZE = 2000;
+struct ZSFStringPoolChunk: public UMemory {
+ ZSFStringPoolChunk *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
+ ZSFStringPoolChunk();
+};
+
+ZSFStringPoolChunk::ZSFStringPoolChunk() {
+ fNext = NULL;
+ fLimit = 0;
+}
+
+ZSFStringPool::ZSFStringPool(UErrorCode &status) {
+ fChunks = NULL;
+ fHash = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fChunks = new ZSFStringPoolChunk;
+ 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;
+ }
+}
+
+
+ZSFStringPool::~ZSFStringPool() {
+ if (fHash != NULL) {
+ uhash_close(fHash);
+ fHash = NULL;
+ }
+
+ while (fChunks != NULL) {
+ ZSFStringPoolChunk *nextChunk = fChunks->fNext;
+ delete fChunks;
+ fChunks = nextChunk;
+ }
+}
+
+static const UChar EmptyString = 0;
+
+const UChar *ZSFStringPool::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;
+ }
+ ZSFStringPoolChunk *oldChunk = fChunks;
+ fChunks = new ZSFStringPoolChunk;
+ 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;
+}
+
+
+//
+// ZSFStringPool::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 *ZSFStringPool::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 *ZSFStringPool::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 ZSFStringPool::freeze() {
+ uhash_close(fHash);
+ fHash = NULL;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-4.6/i18n/zstrfmt.h b/Build/source/libs/icu/icu-4.6/i18n/zstrfmt.h
new file mode 100644
index 00000000000..814b0f800bd
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/zstrfmt.h
@@ -0,0 +1,526 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef ZSTRFMT_H
+#define ZSTRFMT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/calendar.h"
+#include "uhash.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * 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();
+
+ void addValue(void *value, 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
+};
+
+
+/*
+ * ZSFStringPool Pool of (UChar *) strings. Provides for sharing of repeated
+ * strings within ZoneStringFormats.
+ */
+class ZSFStringPoolChunk;
+class ZSFStringPool: public UMemory {
+ public:
+ ZSFStringPool(UErrorCode &status);
+ ~ZSFStringPool();
+
+ /* 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:
+ ZSFStringPoolChunk *fChunks;
+ UHashtable *fHash;
+};
+
+
+/**
+ * TextTrieMap is a trie implementation for supporting
+ * fast prefix match for the string key.
+ */
+class TextTrieMap : public UMemory {
+public:
+ TextTrieMap(UBool ignoreCase);
+ virtual ~TextTrieMap();
+
+ void put(const UnicodeString &key, void *value, ZSFStringPool &sp, 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;
+
+ 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;
+};
+
+
+// Name types, these bit flag are used for zone string lookup
+enum TimeZoneTranslationType {
+ LOCATION = 0x0001,
+ GENERIC_LONG = 0x0002,
+ GENERIC_SHORT = 0x0004,
+ STANDARD_LONG = 0x0008,
+ STANDARD_SHORT = 0x0010,
+ DAYLIGHT_LONG = 0x0020,
+ DAYLIGHT_SHORT = 0x0040
+};
+
+// Name type index, these constants are used for index in the zone strings array.
+enum TimeZoneTranslationTypeIndex {
+ ZSIDX_LOCATION = 0,
+ ZSIDX_LONG_STANDARD,
+ ZSIDX_SHORT_STANDARD,
+ ZSIDX_LONG_DAYLIGHT,
+ ZSIDX_SHORT_DAYLIGHT,
+ ZSIDX_LONG_GENERIC,
+ ZSIDX_SHORT_GENERIC,
+
+ ZSIDX_COUNT
+};
+
+class MessageFormat;
+
+
+/*
+ * ZoneStringInfo is a class holding a localized zone string
+ * information.
+ */
+class ZoneStringInfo : public UMemory {
+public:
+ virtual ~ZoneStringInfo();
+
+ inline UnicodeString& getID(UnicodeString &result) const;
+ inline UnicodeString& getString(UnicodeString &result) const;
+ inline UBool isStandard(void) const;
+ inline UBool isDaylight(void) const;
+ inline UBool isGeneric(void) const;
+
+private:
+ friend class ZoneStringFormat;
+ friend class ZoneStringSearchResultHandler;
+
+ ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
+ TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status);
+
+ const UChar *fId;
+ const UChar *fStr;
+ TimeZoneTranslationType fType;
+};
+
+inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
+ return result.setTo(fId, -1);
+}
+
+inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
+ return result.setTo(fStr, -1);
+}
+
+inline UBool ZoneStringInfo::isStandard(void) const {
+ return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
+}
+
+inline UBool ZoneStringInfo::isDaylight(void) const {
+ return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
+}
+
+inline UBool ZoneStringInfo::isGeneric(void) const {
+ return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT);
+}
+
+class SafeZoneStringFormatPtr;
+
+class ZoneStringFormat : public UMemory {
+public:
+ ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status);
+ ZoneStringFormat(const Locale& locale, UErrorCode &status);
+ virtual ~ZoneStringFormat();
+
+ /* Gets zone string format from cache if available, create it if not cached. */
+ static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status);
+
+ /*
+ * Create a snapshot of old zone strings array for the given date
+ */
+ UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const;
+
+ /* TODO: There is no implementation for this function. Delete declaration? */
+ const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const;
+
+ UnicodeString& getSpecificLongString(const Calendar &cal,
+ UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getSpecificShortString(const Calendar &cal,
+ UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getGenericLongString(const Calendar &cal,
+ UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getGenericShortString(const Calendar &cal,
+ UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getGenericLocationString(const Calendar &cal,
+ UnicodeString &result, UErrorCode &status) const;
+
+ const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+
+ // Following APIs are not used by SimpleDateFormat, but public for testing purpose
+ inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
+
+private:
+ Locale fLocale;
+ UHashtable *fTzidToStrings;
+ UHashtable *fMzidToStrings;
+
+ TextTrieMap fZoneStringsTrie;
+ ZSFStringPool fStringPool;
+
+ UResourceBundle *fZoneStringsArray;
+ UResourceBundle *fMetazoneItem;
+ UResourceBundle *fZoneItem;
+
+ UBool fIsFullyLoaded;
+
+ void loadZone(const UnicodeString &utzid, UErrorCode &status);
+ void addSingleZone(UnicodeString &utzid, UErrorCode &status);
+ void loadFull(UErrorCode &status);
+
+
+ /*
+ * Private method to get a zone string except generic partial location types.
+ */
+ UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
+ UBool commonlyUsedOnly, UnicodeString& result) const;
+
+ /*
+ * Private method to get a generic string, with fallback logic involved,
+ * that is,
+ *
+ * 1. If a generic non-location string is avaiable for the zone, return it.
+ * 2. If a generic non-location string is associated with a metazone and
+ * the zone never use daylight time around the given date, use the standard
+ * string (if available).
+ *
+ * Note: In CLDR1.5.1, the same localization is used for generic and standard.
+ * In this case, we do not use the standard string and do the rest.
+ *
+ * 3. If a generic non-location string is associated with a metazone and
+ * the offset at the given time is different from the preferred zone for the
+ * current locale, then return the generic partial location string (if avaiable)
+ * 4. If a generic non-location string is not available, use generic location
+ * string.
+ */
+ UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const;
+
+ /*
+ * Private method to get a generic partial location string
+ */
+ UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
+ UDate date, UBool commonlyUsedOnly, UnicodeString &result) const;
+
+ /*
+ * Find a prefix matching time zone for the given zone string types.
+ * @param text The text contains a time zone string
+ * @param start The start index within the text
+ * @param types The bit mask representing a set of requested types
+ * @param matchLength Receives the match length
+ * @param status
+ * @return If any zone string matched for the requested types, returns a
+ * ZoneStringInfo for the longest match. If no matches are found for
+ * the requested types, returns a ZoneStringInfo for the longest match
+ * for any other types. If nothing matches at all, returns null.
+ */
+ const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* subFind(const UnicodeString &text, int32_t start, int32_t types,
+ int32_t &matchLength, UErrorCode &status) const;
+
+ UnicodeString& getRegion(UnicodeString &region) const;
+
+ static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
+ static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
+ const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
+ static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
+ static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
+ UnicodeString &displayCountry);
+};
+
+inline UnicodeString&
+ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result);
+}
+
+
+/*
+ * ZoneStrings is a container of localized zone strings used by ZoneStringFormat
+ */
+class ZoneStrings : public UMemory {
+public:
+ ZoneStrings(UnicodeString *strings,
+ int32_t stringsCount,
+ UBool commonlyUsed,
+ UnicodeString **genericPartialLocationStrings,
+ int32_t genericRowCount,
+ int32_t genericColCount,
+ ZSFStringPool &sp,
+ UErrorCode &status);
+ virtual ~ZoneStrings();
+
+ UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const;
+ inline UBool isShortFormatCommonlyUsed(void) const;
+ UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
+ UBool commonlyUsedOnly, UnicodeString &result) const;
+
+private:
+ const UChar **fStrings;
+ int32_t fStringsCount;
+ UBool fIsCommonlyUsed;
+ const UChar * **fGenericPartialLocationStrings;
+ int32_t fGenericPartialLocationRowCount;
+ int32_t fGenericPartialLocationColCount;
+};
+
+inline UBool
+ZoneStrings::isShortFormatCommonlyUsed(void) const {
+ return fIsCommonlyUsed;
+}
+
+/*
+ * ZoneStringSearchResultHandler is an implementation of
+ * TextTrieMapSearchHandler. This class is used by ZoneStringFormat
+ * for collecting search results for localized zone strings.
+ */
+class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler {
+public:
+ ZoneStringSearchResultHandler(UErrorCode &status);
+ virtual ~ZoneStringSearchResultHandler();
+
+ virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
+ int32_t countMatches(void);
+ const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength);
+ void clear(void);
+
+private:
+ UVector fResults;
+ int32_t fMatchLen[ZSIDX_COUNT];
+};
+
+
+/*
+ * ZoneStringFormat cache implementation
+ */
+class ZSFCacheEntry : public UMemory {
+public:
+ ~ZSFCacheEntry();
+
+ void delRef(void);
+ const ZoneStringFormat* getZoneStringFormat(void);
+
+private:
+ friend class ZSFCache;
+
+ ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next);
+
+ Locale fLocale;
+ ZoneStringFormat *fZoneStringFormat;
+ ZSFCacheEntry *fNext;
+ int32_t fRefCount;
+};
+
+class SafeZoneStringFormatPtr : public UMemory {
+public:
+ ~SafeZoneStringFormatPtr();
+ const ZoneStringFormat* get() const;
+
+private:
+ friend class ZSFCache;
+
+ SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry);
+
+ ZSFCacheEntry *fCacheEntry;
+};
+
+class ZSFCache : public UMemory {
+public:
+ ZSFCache(int32_t capacity);
+ ~ZSFCache();
+
+ SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status);
+
+private:
+ int32_t fCapacity;
+ ZSFCacheEntry *fFirst;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // ZSTRFMT_H
diff --git a/Build/source/libs/icu/icu-4.6/i18n/ztrans.cpp b/Build/source/libs/icu/icu-4.6/i18n/ztrans.cpp
new file mode 100644
index 00000000000..58f2e12476d
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/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.6/i18n/ztrans.h b/Build/source/libs/icu/icu-4.6/i18n/ztrans.h
new file mode 100644
index 00000000000..d96198ed0b1
--- /dev/null
+++ b/Build/source/libs/icu/icu-4.6/i18n/ztrans.h
@@ -0,0 +1,188 @@
+/*
+*******************************************************************************
+* Copyright (C) 2009-2010, 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.
+ * @draft ICU 4.4
+ */
+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.
+ * @draft ICU 4.4
+ */
+U_DRAFT ZTrans* U_EXPORT2
+ztrans_open(UDate time, const void* from, const void* to);
+
+/**
+ * Constructs an empty <code>TimeZoneTransition</code>
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT 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.
+ * @draft ICU 4.4
+ */
+U_DRAFT UClassID U_EXPORT2
+ztrans_getDynamicClassID(ZTrans* trans);
+
+#endif
+
+#endif